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