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.8 2019/10/01 16:06:16 christos Exp $"); 13 #endif 14 15 /* \summary: Datagram Congestion Control Protocol (DCCP) printer */ 16 17 #ifdef HAVE_CONFIG_H 18 #include "config.h" 19 #endif 20 21 #include <netdissect-stdinc.h> 22 23 #include <stdio.h> 24 #include <string.h> 25 26 #include "netdissect.h" 27 #include "addrtoname.h" 28 #include "extract.h" 29 #include "ip.h" 30 #include "ip6.h" 31 #include "ipproto.h" 32 33 /* RFC4340: Datagram Congestion Control Protocol (DCCP) */ 34 35 /** 36 * struct dccp_hdr - generic part of DCCP packet header, with a 24-bit 37 * sequence number 38 * 39 * @dccph_sport - Relevant port on the endpoint that sent this packet 40 * @dccph_dport - Relevant port on the other endpoint 41 * @dccph_doff - Data Offset from the start of the DCCP header, in 32-bit words 42 * @dccph_ccval - Used by the HC-Sender CCID 43 * @dccph_cscov - Parts of the packet that are covered by the Checksum field 44 * @dccph_checksum - Internet checksum, depends on dccph_cscov 45 * @dccph_x - 0 = 24 bit sequence number, 1 = 48 46 * @dccph_type - packet type, see DCCP_PKT_ prefixed macros 47 * @dccph_seq - 24-bit sequence number 48 */ 49 struct dccp_hdr { 50 uint16_t dccph_sport, 51 dccph_dport; 52 uint8_t dccph_doff; 53 uint8_t dccph_ccval_cscov; 54 uint16_t dccph_checksum; 55 uint8_t dccph_xtr; 56 uint8_t dccph_seq[3]; 57 } UNALIGNED; 58 59 /** 60 * struct dccp_hdr_ext - generic part of DCCP packet header, with a 48-bit 61 * sequence number 62 * 63 * @dccph_sport - Relevant port on the endpoint that sent this packet 64 * @dccph_dport - Relevant port on the other endpoint 65 * @dccph_doff - Data Offset from the start of the DCCP header, in 32-bit words 66 * @dccph_ccval - Used by the HC-Sender CCID 67 * @dccph_cscov - Parts of the packet that are covered by the Checksum field 68 * @dccph_checksum - Internet checksum, depends on dccph_cscov 69 * @dccph_x - 0 = 24 bit sequence number, 1 = 48 70 * @dccph_type - packet type, see DCCP_PKT_ prefixed macros 71 * @dccph_seq - 48-bit sequence number 72 */ 73 struct dccp_hdr_ext { 74 uint16_t dccph_sport, 75 dccph_dport; 76 uint8_t dccph_doff; 77 uint8_t dccph_ccval_cscov; 78 uint16_t dccph_checksum; 79 uint8_t dccph_xtr; 80 uint8_t reserved; 81 uint8_t dccph_seq[6]; 82 } UNALIGNED; 83 84 #define DCCPH_CCVAL(dh) (((dh)->dccph_ccval_cscov >> 4) & 0xF) 85 #define DCCPH_CSCOV(dh) (((dh)->dccph_ccval_cscov) & 0xF) 86 87 #define DCCPH_X(dh) ((dh)->dccph_xtr & 1) 88 #define DCCPH_TYPE(dh) (((dh)->dccph_xtr >> 1) & 0xF) 89 90 /** 91 * struct dccp_hdr_request - Conection initiation request header 92 * 93 * @dccph_req_service - Service to which the client app wants to connect 94 */ 95 struct dccp_hdr_request { 96 uint32_t dccph_req_service; 97 } UNALIGNED; 98 99 /** 100 * struct dccp_hdr_response - Conection initiation response header 101 * 102 * @dccph_resp_ack - 48 bit ack number, contains GSR 103 * @dccph_resp_service - Echoes the Service Code on a received DCCP-Request 104 */ 105 struct dccp_hdr_response { 106 uint8_t dccph_resp_ack[8]; /* always 8 bytes */ 107 uint32_t dccph_resp_service; 108 } UNALIGNED; 109 110 /** 111 * struct dccp_hdr_reset - Unconditionally shut down a connection 112 * 113 * @dccph_resp_ack - 48 bit ack number 114 * @dccph_reset_service - Echoes the Service Code on a received DCCP-Request 115 */ 116 struct dccp_hdr_reset { 117 uint8_t dccph_reset_ack[8]; /* always 8 bytes */ 118 uint8_t dccph_reset_code, 119 dccph_reset_data[3]; 120 } UNALIGNED; 121 122 enum dccp_pkt_type { 123 DCCP_PKT_REQUEST = 0, 124 DCCP_PKT_RESPONSE, 125 DCCP_PKT_DATA, 126 DCCP_PKT_ACK, 127 DCCP_PKT_DATAACK, 128 DCCP_PKT_CLOSEREQ, 129 DCCP_PKT_CLOSE, 130 DCCP_PKT_RESET, 131 DCCP_PKT_SYNC, 132 DCCP_PKT_SYNCACK 133 }; 134 135 static const struct tok dccp_pkt_type_str[] = { 136 { DCCP_PKT_REQUEST, "DCCP-Request" }, 137 { DCCP_PKT_RESPONSE, "DCCP-Response" }, 138 { DCCP_PKT_DATA, "DCCP-Data" }, 139 { DCCP_PKT_ACK, "DCCP-Ack" }, 140 { DCCP_PKT_DATAACK, "DCCP-DataAck" }, 141 { DCCP_PKT_CLOSEREQ, "DCCP-CloseReq" }, 142 { DCCP_PKT_CLOSE, "DCCP-Close" }, 143 { DCCP_PKT_RESET, "DCCP-Reset" }, 144 { DCCP_PKT_SYNC, "DCCP-Sync" }, 145 { DCCP_PKT_SYNCACK, "DCCP-SyncAck" }, 146 { 0, NULL} 147 }; 148 149 enum dccp_reset_codes { 150 DCCP_RESET_CODE_UNSPECIFIED = 0, 151 DCCP_RESET_CODE_CLOSED, 152 DCCP_RESET_CODE_ABORTED, 153 DCCP_RESET_CODE_NO_CONNECTION, 154 DCCP_RESET_CODE_PACKET_ERROR, 155 DCCP_RESET_CODE_OPTION_ERROR, 156 DCCP_RESET_CODE_MANDATORY_ERROR, 157 DCCP_RESET_CODE_CONNECTION_REFUSED, 158 DCCP_RESET_CODE_BAD_SERVICE_CODE, 159 DCCP_RESET_CODE_TOO_BUSY, 160 DCCP_RESET_CODE_BAD_INIT_COOKIE, 161 DCCP_RESET_CODE_AGGRESSION_PENALTY, 162 __DCCP_RESET_CODE_LAST 163 }; 164 165 static const char tstr[] = "[|dccp]"; 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 inline u_int dccp_csum_coverage(const struct dccp_hdr* dh, u_int len) 196 { 197 u_int cov; 198 199 if (DCCPH_CSCOV(dh) == 0) 200 return len; 201 cov = (dh->dccph_doff + DCCPH_CSCOV(dh) - 1) * sizeof(uint32_t); 202 return (cov > len)? len : cov; 203 } 204 205 static int dccp_cksum(netdissect_options *ndo, const struct ip *ip, 206 const struct dccp_hdr *dh, u_int len) 207 { 208 return nextproto4_cksum(ndo, ip, (const uint8_t *)(const void *)dh, len, 209 dccp_csum_coverage(dh, len), IPPROTO_DCCP); 210 } 211 212 static int dccp6_cksum(netdissect_options *ndo, const struct ip6_hdr *ip6, 213 const struct dccp_hdr *dh, u_int len) 214 { 215 return nextproto6_cksum(ndo, ip6, (const uint8_t *)(const void *)dh, len, 216 dccp_csum_coverage(dh, len), IPPROTO_DCCP); 217 } 218 219 static const char *dccp_reset_code(uint8_t code) 220 { 221 if (code >= __DCCP_RESET_CODE_LAST) 222 return "invalid"; 223 return dccp_reset_codes[code]; 224 } 225 226 static uint64_t dccp_seqno(const u_char *bp) 227 { 228 const struct dccp_hdr *dh = (const struct dccp_hdr *)bp; 229 uint64_t seqno; 230 231 if (DCCPH_X(dh) != 0) { 232 const struct dccp_hdr_ext *dhx = (const struct dccp_hdr_ext *)bp; 233 seqno = EXTRACT_48BITS(dhx->dccph_seq); 234 } else { 235 seqno = EXTRACT_24BITS(dh->dccph_seq); 236 } 237 238 return seqno; 239 } 240 241 static inline unsigned int dccp_basic_hdr_len(const struct dccp_hdr *dh) 242 { 243 return DCCPH_X(dh) ? sizeof(struct dccp_hdr_ext) : sizeof(struct dccp_hdr); 244 } 245 246 static void dccp_print_ack_no(netdissect_options *ndo, const u_char *bp) 247 { 248 const struct dccp_hdr *dh = (const struct dccp_hdr *)bp; 249 const u_char *ackp = bp + dccp_basic_hdr_len(dh); 250 uint64_t ackno; 251 252 if (DCCPH_X(dh) != 0) { 253 ND_TCHECK2(*ackp, 8); 254 ackno = EXTRACT_48BITS(ackp + 2); 255 } else { 256 ND_TCHECK2(*ackp, 4); 257 ackno = EXTRACT_24BITS(ackp + 1); 258 } 259 260 ND_PRINT((ndo, "(ack=%" PRIu64 ") ", ackno)); 261 trunc: 262 return; 263 } 264 265 static 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 - lenght of ip packet 272 */ 273 void dccp_print(netdissect_options *ndo, const u_char *bp, const u_char *data2, 274 u_int len) 275 { 276 const struct dccp_hdr *dh; 277 const struct ip *ip; 278 const struct ip6_hdr *ip6; 279 const u_char *cp; 280 u_short sport, dport; 281 u_int hlen; 282 u_int fixed_hdrlen; 283 uint8_t dccph_type; 284 285 dh = (const struct dccp_hdr *)bp; 286 287 ip = (const struct ip *)data2; 288 if (IP_V(ip) == 6) 289 ip6 = (const struct ip6_hdr *)data2; 290 else 291 ip6 = NULL; 292 293 /* make sure we have enough data to look at the X bit */ 294 cp = (const u_char *)(dh + 1); 295 if (cp > ndo->ndo_snapend) { 296 ND_PRINT((ndo, "[Invalid packet|dccp]")); 297 return; 298 } 299 if (len < sizeof(struct dccp_hdr)) { 300 ND_PRINT((ndo, "truncated-dccp - %u bytes missing!", 301 len - (u_int)sizeof(struct dccp_hdr))); 302 return; 303 } 304 305 /* get the length of the generic header */ 306 fixed_hdrlen = dccp_basic_hdr_len(dh); 307 if (len < fixed_hdrlen) { 308 ND_PRINT((ndo, "truncated-dccp - %u bytes missing!", 309 len - fixed_hdrlen)); 310 return; 311 } 312 ND_TCHECK2(*dh, fixed_hdrlen); 313 314 sport = EXTRACT_16BITS(&dh->dccph_sport); 315 dport = EXTRACT_16BITS(&dh->dccph_dport); 316 hlen = dh->dccph_doff * 4; 317 318 if (ip6) { 319 ND_PRINT((ndo, "%s.%d > %s.%d: ", 320 ip6addr_string(ndo, &ip6->ip6_src), sport, 321 ip6addr_string(ndo, &ip6->ip6_dst), dport)); 322 } else { 323 ND_PRINT((ndo, "%s.%d > %s.%d: ", 324 ipaddr_string(ndo, &ip->ip_src), sport, 325 ipaddr_string(ndo, &ip->ip_dst), dport)); 326 } 327 328 ND_PRINT((ndo, "DCCP")); 329 330 if (ndo->ndo_qflag) { 331 ND_PRINT((ndo, " %d", len - hlen)); 332 if (hlen > len) { 333 ND_PRINT((ndo, " [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((ndo, " (CCVal %d, CsCov %d, ", DCCPH_CCVAL(dh), DCCPH_CSCOV(dh))); 342 } 343 344 /* checksum calculation */ 345 if (ndo->ndo_vflag && ND_TTEST2(bp[0], len)) { 346 uint16_t sum = 0, dccp_sum; 347 348 dccp_sum = EXTRACT_16BITS(&dh->dccph_checksum); 349 ND_PRINT((ndo, "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((ndo, "(incorrect -> 0x%04x)",in_cksum_shouldbe(dccp_sum, sum))); 356 else 357 ND_PRINT((ndo, "(correct)")); 358 } 359 360 if (ndo->ndo_vflag) 361 ND_PRINT((ndo, ")")); 362 ND_PRINT((ndo, " ")); 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((ndo, "truncated-%s - %u bytes missing!", 372 tok2str(dccp_pkt_type_str, "", dccph_type), 373 len - fixed_hdrlen)); 374 return; 375 } 376 ND_TCHECK(*dhr); 377 ND_PRINT((ndo, "%s (service=%d) ", 378 tok2str(dccp_pkt_type_str, "", dccph_type), 379 EXTRACT_32BITS(&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((ndo, "truncated-%s - %u bytes missing!", 388 tok2str(dccp_pkt_type_str, "", dccph_type), 389 len - fixed_hdrlen)); 390 return; 391 } 392 ND_TCHECK(*dhr); 393 ND_PRINT((ndo, "%s (service=%d) ", 394 tok2str(dccp_pkt_type_str, "", dccph_type), 395 EXTRACT_32BITS(&dhr->dccph_resp_service))); 396 break; 397 } 398 case DCCP_PKT_DATA: 399 ND_PRINT((ndo, "%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((ndo, "truncated-%s - %u bytes missing!", 405 tok2str(dccp_pkt_type_str, "", dccph_type), 406 len - fixed_hdrlen)); 407 return; 408 } 409 ND_PRINT((ndo, "%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((ndo, "truncated-%s - %u bytes missing!", 416 tok2str(dccp_pkt_type_str, "", dccph_type), 417 len - fixed_hdrlen)); 418 return; 419 } 420 ND_PRINT((ndo, "%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((ndo, "truncated-%s - %u bytes missing!", 427 tok2str(dccp_pkt_type_str, "", dccph_type), 428 len - fixed_hdrlen)); 429 return; 430 } 431 ND_PRINT((ndo, "%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((ndo, "truncated-%s - %u bytes missing!", 437 tok2str(dccp_pkt_type_str, "", dccph_type), 438 len - fixed_hdrlen)); 439 return; 440 } 441 ND_PRINT((ndo, "%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((ndo, "truncated-%s - %u bytes missing!", 449 tok2str(dccp_pkt_type_str, "", dccph_type), 450 len - fixed_hdrlen)); 451 return; 452 } 453 ND_TCHECK(*dhr); 454 ND_PRINT((ndo, "%s (code=%s) ", 455 tok2str(dccp_pkt_type_str, "", dccph_type), 456 dccp_reset_code(dhr->dccph_reset_code))); 457 break; 458 } 459 case DCCP_PKT_SYNC: 460 fixed_hdrlen += 8; 461 if (len < fixed_hdrlen) { 462 ND_PRINT((ndo, "truncated-%s - %u bytes missing!", 463 tok2str(dccp_pkt_type_str, "", dccph_type), 464 len - fixed_hdrlen)); 465 return; 466 } 467 ND_PRINT((ndo, "%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((ndo, "truncated-%s - %u bytes missing!", 473 tok2str(dccp_pkt_type_str, "", dccph_type), 474 len - fixed_hdrlen)); 475 return; 476 } 477 ND_PRINT((ndo, "%s ", tok2str(dccp_pkt_type_str, "", dccph_type))); 478 break; 479 default: 480 ND_PRINT((ndo, "%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((ndo, "seq %" PRIu64, dccp_seqno(bp))); 492 493 /* process options */ 494 if (hlen > fixed_hdrlen){ 495 u_int optlen; 496 cp = bp + fixed_hdrlen; 497 ND_PRINT((ndo, " <")); 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((ndo, ", ")); 509 } 510 ND_PRINT((ndo, ">")); 511 } 512 return; 513 trunc: 514 ND_PRINT((ndo, "%s", tstr)); 515 return; 516 } 517 518 static const struct tok dccp_option_values[] = { 519 { 0, "nop" }, 520 { 1, "mandatory" }, 521 { 2, "slowreceiver" }, 522 { 32, "change_l" }, 523 { 33, "confirm_l" }, 524 { 34, "change_r" }, 525 { 35, "confirm_r" }, 526 { 36, "initcookie" }, 527 { 37, "ndp_count" }, 528 { 38, "ack_vector0" }, 529 { 39, "ack_vector1" }, 530 { 40, "data_dropped" }, 531 { 41, "timestamp" }, 532 { 42, "timestamp_echo" }, 533 { 43, "elapsed_time" }, 534 { 44, "data_checksum" }, 535 { 0, NULL } 536 }; 537 538 static int 539 dccp_print_option(netdissect_options *ndo, const u_char *option, u_int hlen) 540 { 541 uint8_t optlen, i; 542 543 ND_TCHECK(*option); 544 545 if (*option >= 32) { 546 ND_TCHECK(*(option+1)); 547 optlen = *(option +1); 548 if (optlen < 2) { 549 if (*option >= 128) 550 ND_PRINT((ndo, "CCID option %u optlen too short", *option)); 551 else 552 ND_PRINT((ndo, "%s optlen too short", 553 tok2str(dccp_option_values, "Option %u", *option))); 554 return 0; 555 } 556 } else 557 optlen = 1; 558 559 if (hlen < optlen) { 560 if (*option >= 128) 561 ND_PRINT((ndo, "CCID option %u optlen goes past header length", 562 *option)); 563 else 564 ND_PRINT((ndo, "%s optlen goes past header length", 565 tok2str(dccp_option_values, "Option %u", *option))); 566 return 0; 567 } 568 ND_TCHECK2(*option, optlen); 569 570 if (*option >= 128) { 571 ND_PRINT((ndo, "CCID option %d", *option)); 572 switch (optlen) { 573 case 4: 574 ND_PRINT((ndo, " %u", EXTRACT_16BITS(option + 2))); 575 break; 576 case 6: 577 ND_PRINT((ndo, " %u", EXTRACT_32BITS(option + 2))); 578 break; 579 default: 580 break; 581 } 582 } else { 583 ND_PRINT((ndo, "%s", tok2str(dccp_option_values, "Option %u", *option))); 584 switch (*option) { 585 case 32: 586 case 33: 587 case 34: 588 case 35: 589 if (optlen < 3) { 590 ND_PRINT((ndo, " optlen too short")); 591 return optlen; 592 } 593 if (*(option + 2) < 10){ 594 ND_PRINT((ndo, " %s", dccp_feature_nums[*(option + 2)])); 595 for (i = 0; i < optlen - 3; i++) 596 ND_PRINT((ndo, " %d", *(option + 3 + i))); 597 } 598 break; 599 case 36: 600 if (optlen > 2) { 601 ND_PRINT((ndo, " 0x")); 602 for (i = 0; i < optlen - 2; i++) 603 ND_PRINT((ndo, "%02x", *(option + 2 + i))); 604 } 605 break; 606 case 37: 607 for (i = 0; i < optlen - 2; i++) 608 ND_PRINT((ndo, " %d", *(option + 2 + i))); 609 break; 610 case 38: 611 if (optlen > 2) { 612 ND_PRINT((ndo, " 0x")); 613 for (i = 0; i < optlen - 2; i++) 614 ND_PRINT((ndo, "%02x", *(option + 2 + i))); 615 } 616 break; 617 case 39: 618 if (optlen > 2) { 619 ND_PRINT((ndo, " 0x")); 620 for (i = 0; i < optlen - 2; i++) 621 ND_PRINT((ndo, "%02x", *(option + 2 + i))); 622 } 623 break; 624 case 40: 625 if (optlen > 2) { 626 ND_PRINT((ndo, " 0x")); 627 for (i = 0; i < optlen - 2; i++) 628 ND_PRINT((ndo, "%02x", *(option + 2 + i))); 629 } 630 break; 631 case 41: 632 /* 633 * 13.1. Timestamp Option 634 * 635 * +--------+--------+--------+--------+--------+--------+ 636 * |00101001|00000110| Timestamp Value | 637 * +--------+--------+--------+--------+--------+--------+ 638 * Type=41 Length=6 639 */ 640 if (optlen == 6) 641 ND_PRINT((ndo, " %u", EXTRACT_32BITS(option + 2))); 642 else 643 ND_PRINT((ndo, " [optlen != 6]")); 644 break; 645 case 42: 646 /* 647 * 13.3. Timestamp Echo Option 648 * 649 * +--------+--------+--------+--------+--------+--------+ 650 * |00101010|00000110| Timestamp Echo | 651 * +--------+--------+--------+--------+--------+--------+ 652 * Type=42 Len=6 653 * 654 * +--------+--------+------- ... -------+--------+--------+ 655 * |00101010|00001000| Timestamp Echo | Elapsed Time | 656 * +--------+--------+------- ... -------+--------+--------+ 657 * Type=42 Len=8 (4 bytes) 658 * 659 * +--------+--------+------- ... -------+------- ... -------+ 660 * |00101010|00001010| Timestamp Echo | Elapsed Time | 661 * +--------+--------+------- ... -------+------- ... -------+ 662 * Type=42 Len=10 (4 bytes) (4 bytes) 663 */ 664 switch (optlen) { 665 case 6: 666 ND_PRINT((ndo, " %u", EXTRACT_32BITS(option + 2))); 667 break; 668 case 8: 669 ND_PRINT((ndo, " %u", EXTRACT_32BITS(option + 2))); 670 ND_PRINT((ndo, " (elapsed time %u)", EXTRACT_16BITS(option + 6))); 671 break; 672 case 10: 673 ND_PRINT((ndo, " %u", EXTRACT_32BITS(option + 2))); 674 ND_PRINT((ndo, " (elapsed time %u)", EXTRACT_32BITS(option + 6))); 675 break; 676 default: 677 ND_PRINT((ndo, " [optlen != 6 or 8 or 10]")); 678 break; 679 } 680 break; 681 case 43: 682 if (optlen == 6) 683 ND_PRINT((ndo, " %u", EXTRACT_32BITS(option + 2))); 684 else if (optlen == 4) 685 ND_PRINT((ndo, " %u", EXTRACT_16BITS(option + 2))); 686 else 687 ND_PRINT((ndo, " [optlen != 4 or 6]")); 688 break; 689 case 44: 690 if (optlen > 2) { 691 ND_PRINT((ndo, " ")); 692 for (i = 0; i < optlen - 2; i++) 693 ND_PRINT((ndo, "%02x", *(option + 2 + i))); 694 } 695 break; 696 } 697 } 698 699 return optlen; 700 trunc: 701 ND_PRINT((ndo, "%s", tstr)); 702 return 0; 703 } 704