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