1 /* 2 * Redistribution and use in source and binary forms, with or without 3 * modification, are permitted provided that: (1) source code 4 * distributions retain the above copyright notice and this paragraph 5 * in its entirety, and (2) distributions including binary code include 6 * the above copyright notice and this paragraph in its entirety in 7 * the documentation or other materials provided with the distribution. 8 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 9 * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT 10 * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 11 * FOR A PARTICULAR PURPOSE. 12 * 13 * Original code by Hannes Gredler (hannes@gredler.at) 14 * and Steinar Haug (sthaug@nethelp.no) 15 */ 16 17 /* \summary: Label Distribution Protocol (LDP) printer */ 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 "extract.h" 27 #include "addrtoname.h" 28 29 #include "l2vpn.h" 30 #include "af.h" 31 32 33 /* 34 * ldp common header 35 * 36 * 0 1 2 3 37 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 38 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 39 * | Version | PDU Length | 40 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 41 * | LDP Identifier | 42 * + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 43 * | | 44 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 45 * 46 */ 47 48 struct ldp_common_header { 49 nd_uint16_t version; 50 nd_uint16_t pdu_length; 51 nd_ipv4 lsr_id; 52 nd_uint16_t label_space; 53 }; 54 55 #define LDP_VERSION 1 56 57 /* 58 * ldp message header 59 * 60 * 0 1 2 3 61 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 62 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 63 * |U| Message Type | Message Length | 64 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 65 * | Message ID | 66 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 67 * | | 68 * + + 69 * | Mandatory Parameters | 70 * + + 71 * | | 72 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 73 * | | 74 * + + 75 * | Optional Parameters | 76 * + + 77 * | | 78 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 79 */ 80 81 struct ldp_msg_header { 82 nd_uint16_t type; 83 nd_uint16_t length; 84 nd_uint32_t id; 85 }; 86 87 #define LDP_MASK_MSG_TYPE(x) ((x)&0x7fff) 88 #define LDP_MASK_U_BIT(x) ((x)&0x8000) 89 90 #define LDP_MSG_NOTIF 0x0001 91 #define LDP_MSG_HELLO 0x0100 92 #define LDP_MSG_INIT 0x0200 93 #define LDP_MSG_KEEPALIVE 0x0201 94 #define LDP_MSG_ADDRESS 0x0300 95 #define LDP_MSG_ADDRESS_WITHDRAW 0x0301 96 #define LDP_MSG_LABEL_MAPPING 0x0400 97 #define LDP_MSG_LABEL_REQUEST 0x0401 98 #define LDP_MSG_LABEL_WITHDRAW 0x0402 99 #define LDP_MSG_LABEL_RELEASE 0x0403 100 #define LDP_MSG_LABEL_ABORT_REQUEST 0x0404 101 102 #define LDP_VENDOR_PRIVATE_MIN 0x3e00 103 #define LDP_VENDOR_PRIVATE_MAX 0x3eff 104 #define LDP_EXPERIMENTAL_MIN 0x3f00 105 #define LDP_EXPERIMENTAL_MAX 0x3fff 106 107 static const struct tok ldp_msg_values[] = { 108 { LDP_MSG_NOTIF, "Notification" }, 109 { LDP_MSG_HELLO, "Hello" }, 110 { LDP_MSG_INIT, "Initialization" }, 111 { LDP_MSG_KEEPALIVE, "Keepalive" }, 112 { LDP_MSG_ADDRESS, "Address" }, 113 { LDP_MSG_ADDRESS_WITHDRAW, "Address Withdraw" }, 114 { LDP_MSG_LABEL_MAPPING, "Label Mapping" }, 115 { LDP_MSG_LABEL_REQUEST, "Label Request" }, 116 { LDP_MSG_LABEL_WITHDRAW, "Label Withdraw" }, 117 { LDP_MSG_LABEL_RELEASE, "Label Release" }, 118 { LDP_MSG_LABEL_ABORT_REQUEST, "Label Abort Request" }, 119 { 0, NULL} 120 }; 121 122 #define LDP_MASK_TLV_TYPE(x) ((x)&0x3fff) 123 #define LDP_MASK_F_BIT(x) ((x)&0x4000) 124 125 #define LDP_TLV_FEC 0x0100 126 #define LDP_TLV_ADDRESS_LIST 0x0101 127 #define LDP_TLV_ADDRESS_LIST_AFNUM_LEN 2 128 #define LDP_TLV_HOP_COUNT 0x0103 129 #define LDP_TLV_PATH_VECTOR 0x0104 130 #define LDP_TLV_GENERIC_LABEL 0x0200 131 #define LDP_TLV_ATM_LABEL 0x0201 132 #define LDP_TLV_FR_LABEL 0x0202 133 #define LDP_TLV_STATUS 0x0300 134 #define LDP_TLV_EXTD_STATUS 0x0301 135 #define LDP_TLV_RETURNED_PDU 0x0302 136 #define LDP_TLV_RETURNED_MSG 0x0303 137 #define LDP_TLV_COMMON_HELLO 0x0400 138 #define LDP_TLV_IPV4_TRANSPORT_ADDR 0x0401 139 #define LDP_TLV_CONFIG_SEQ_NUMBER 0x0402 140 #define LDP_TLV_IPV6_TRANSPORT_ADDR 0x0403 141 #define LDP_TLV_COMMON_SESSION 0x0500 142 #define LDP_TLV_ATM_SESSION_PARM 0x0501 143 #define LDP_TLV_FR_SESSION_PARM 0x0502 144 #define LDP_TLV_FT_SESSION 0x0503 145 #define LDP_TLV_LABEL_REQUEST_MSG_ID 0x0600 146 #define LDP_TLV_MTU 0x0601 /* rfc 3988 */ 147 148 static const struct tok ldp_tlv_values[] = { 149 { LDP_TLV_FEC, "FEC" }, 150 { LDP_TLV_ADDRESS_LIST, "Address List" }, 151 { LDP_TLV_HOP_COUNT, "Hop Count" }, 152 { LDP_TLV_PATH_VECTOR, "Path Vector" }, 153 { LDP_TLV_GENERIC_LABEL, "Generic Label" }, 154 { LDP_TLV_ATM_LABEL, "ATM Label" }, 155 { LDP_TLV_FR_LABEL, "Frame-Relay Label" }, 156 { LDP_TLV_STATUS, "Status" }, 157 { LDP_TLV_EXTD_STATUS, "Extended Status" }, 158 { LDP_TLV_RETURNED_PDU, "Returned PDU" }, 159 { LDP_TLV_RETURNED_MSG, "Returned Message" }, 160 { LDP_TLV_COMMON_HELLO, "Common Hello Parameters" }, 161 { LDP_TLV_IPV4_TRANSPORT_ADDR, "IPv4 Transport Address" }, 162 { LDP_TLV_CONFIG_SEQ_NUMBER, "Configuration Sequence Number" }, 163 { LDP_TLV_IPV6_TRANSPORT_ADDR, "IPv6 Transport Address" }, 164 { LDP_TLV_COMMON_SESSION, "Common Session Parameters" }, 165 { LDP_TLV_ATM_SESSION_PARM, "ATM Session Parameters" }, 166 { LDP_TLV_FR_SESSION_PARM, "Frame-Relay Session Parameters" }, 167 { LDP_TLV_FT_SESSION, "Fault-Tolerant Session Parameters" }, 168 { LDP_TLV_LABEL_REQUEST_MSG_ID, "Label Request Message ID" }, 169 { LDP_TLV_MTU, "MTU" }, 170 { 0, NULL} 171 }; 172 173 #define LDP_FEC_WILDCARD 0x01 174 #define LDP_FEC_PREFIX 0x02 175 #define LDP_FEC_HOSTADDRESS 0x03 176 /* From RFC 4906; should probably be updated to RFC 4447 (e.g., VC -> PW) */ 177 #define LDP_FEC_MARTINI_VC 0x80 178 179 static const struct tok ldp_fec_values[] = { 180 { LDP_FEC_WILDCARD, "Wildcard" }, 181 { LDP_FEC_PREFIX, "Prefix" }, 182 { LDP_FEC_HOSTADDRESS, "Host address" }, 183 { LDP_FEC_MARTINI_VC, "Martini VC" }, 184 { 0, NULL} 185 }; 186 187 #define LDP_FEC_MARTINI_IFPARM_MTU 0x01 188 #define LDP_FEC_MARTINI_IFPARM_DESC 0x03 189 #define LDP_FEC_MARTINI_IFPARM_VCCV 0x0c 190 191 static const struct tok ldp_fec_martini_ifparm_values[] = { 192 { LDP_FEC_MARTINI_IFPARM_MTU, "MTU" }, 193 { LDP_FEC_MARTINI_IFPARM_DESC, "Description" }, 194 { LDP_FEC_MARTINI_IFPARM_VCCV, "VCCV" }, 195 { 0, NULL} 196 }; 197 198 /* draft-ietf-pwe3-vccv-04.txt */ 199 static const struct tok ldp_fec_martini_ifparm_vccv_cc_values[] = { 200 { 0x01, "PWE3 control word" }, 201 { 0x02, "MPLS Router Alert Label" }, 202 { 0x04, "MPLS inner label TTL = 1" }, 203 { 0, NULL} 204 }; 205 206 /* draft-ietf-pwe3-vccv-04.txt */ 207 static const struct tok ldp_fec_martini_ifparm_vccv_cv_values[] = { 208 { 0x01, "ICMP Ping" }, 209 { 0x02, "LSP Ping" }, 210 { 0x04, "BFD" }, 211 { 0, NULL} 212 }; 213 214 static u_int ldp_pdu_print(netdissect_options *, const u_char *); 215 216 /* 217 * ldp tlv header 218 * 219 * 0 1 2 3 220 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 221 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 222 * |U|F| Type | Length | 223 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 224 * | | 225 * | Value | 226 * ~ ~ 227 * | | 228 * | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 229 * | | 230 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 231 */ 232 233 #define TLV_TCHECK(minlen) \ 234 if (tlv_tlen < minlen) { \ 235 ND_PRINT(" [tlv length %u < %u]", tlv_tlen, minlen); \ 236 nd_print_invalid(ndo); \ 237 goto invalid; \ 238 } 239 240 static u_int 241 ldp_tlv_print(netdissect_options *ndo, 242 const u_char *tptr, 243 u_int msg_tlen) 244 { 245 struct ldp_tlv_header { 246 nd_uint16_t type; 247 nd_uint16_t length; 248 }; 249 250 const struct ldp_tlv_header *ldp_tlv_header; 251 u_short tlv_type,tlv_len,tlv_tlen,af,ft_flags; 252 u_char fec_type; 253 u_int ui,vc_info_len, vc_info_tlv_type, vc_info_tlv_len,idx; 254 char buf[100]; 255 int i; 256 257 ldp_tlv_header = (const struct ldp_tlv_header *)tptr; 258 ND_TCHECK_SIZE(ldp_tlv_header); 259 tlv_len=GET_BE_U_2(ldp_tlv_header->length); 260 if (tlv_len + 4U > msg_tlen) { 261 ND_PRINT("\n\t\t TLV contents go past end of message"); 262 return 0; 263 } 264 tlv_tlen=tlv_len; 265 tlv_type=LDP_MASK_TLV_TYPE(GET_BE_U_2(ldp_tlv_header->type)); 266 267 /* FIXME vendor private / experimental check */ 268 ND_PRINT("\n\t %s TLV (0x%04x), length: %u, Flags: [%s and %s forward if unknown]", 269 tok2str(ldp_tlv_values, 270 "Unknown", 271 tlv_type), 272 tlv_type, 273 tlv_len, 274 LDP_MASK_U_BIT(GET_BE_U_2(ldp_tlv_header->type)) ? "continue processing" : "ignore", 275 LDP_MASK_F_BIT(GET_BE_U_2(ldp_tlv_header->type)) ? "do" : "don't"); 276 277 tptr+=sizeof(struct ldp_tlv_header); 278 279 switch(tlv_type) { 280 281 case LDP_TLV_COMMON_HELLO: 282 TLV_TCHECK(4); 283 ND_PRINT("\n\t Hold Time: %us, Flags: [%s Hello%s]", 284 GET_BE_U_2(tptr), 285 (GET_BE_U_2(tptr + 2)&0x8000) ? "Targeted" : "Link", 286 (GET_BE_U_2(tptr + 2)&0x4000) ? ", Request for targeted Hellos" : ""); 287 break; 288 289 case LDP_TLV_IPV4_TRANSPORT_ADDR: 290 TLV_TCHECK(4); 291 ND_PRINT("\n\t IPv4 Transport Address: %s", GET_IPADDR_STRING(tptr)); 292 break; 293 case LDP_TLV_IPV6_TRANSPORT_ADDR: 294 TLV_TCHECK(16); 295 ND_PRINT("\n\t IPv6 Transport Address: %s", GET_IP6ADDR_STRING(tptr)); 296 break; 297 case LDP_TLV_CONFIG_SEQ_NUMBER: 298 TLV_TCHECK(4); 299 ND_PRINT("\n\t Sequence Number: %u", GET_BE_U_4(tptr)); 300 break; 301 302 case LDP_TLV_ADDRESS_LIST: 303 TLV_TCHECK(LDP_TLV_ADDRESS_LIST_AFNUM_LEN); 304 af = GET_BE_U_2(tptr); 305 tptr+=LDP_TLV_ADDRESS_LIST_AFNUM_LEN; 306 tlv_tlen -= LDP_TLV_ADDRESS_LIST_AFNUM_LEN; 307 ND_PRINT("\n\t Address Family: %s, addresses", 308 tok2str(af_values, "Unknown (%u)", af)); 309 switch (af) { 310 case AFNUM_INET: 311 while(tlv_tlen >= sizeof(nd_ipv4)) { 312 ND_PRINT(" %s", GET_IPADDR_STRING(tptr)); 313 tlv_tlen-=sizeof(nd_ipv4); 314 tptr+=sizeof(nd_ipv4); 315 } 316 break; 317 case AFNUM_INET6: 318 while(tlv_tlen >= sizeof(nd_ipv6)) { 319 ND_PRINT(" %s", GET_IP6ADDR_STRING(tptr)); 320 tlv_tlen-=sizeof(nd_ipv6); 321 tptr+=sizeof(nd_ipv6); 322 } 323 break; 324 default: 325 /* unknown AF */ 326 break; 327 } 328 break; 329 330 case LDP_TLV_COMMON_SESSION: 331 TLV_TCHECK(8); 332 ND_PRINT("\n\t Version: %u, Keepalive: %us, Flags: [Downstream %s, Loop Detection %s]", 333 GET_BE_U_2(tptr), GET_BE_U_2(tptr + 2), 334 (GET_BE_U_2(tptr + 6)&0x8000) ? "On Demand" : "Unsolicited", 335 (GET_BE_U_2(tptr + 6)&0x4000) ? "Enabled" : "Disabled" 336 ); 337 break; 338 339 case LDP_TLV_FEC: 340 TLV_TCHECK(1); 341 fec_type = GET_U_1(tptr); 342 ND_PRINT("\n\t %s FEC (0x%02x)", 343 tok2str(ldp_fec_values, "Unknown", fec_type), 344 fec_type); 345 346 tptr+=1; 347 tlv_tlen-=1; 348 switch(fec_type) { 349 350 case LDP_FEC_WILDCARD: 351 break; 352 case LDP_FEC_PREFIX: 353 TLV_TCHECK(2); 354 af = GET_BE_U_2(tptr); 355 tptr+=2; 356 tlv_tlen-=2; 357 if (af == AFNUM_INET) { 358 i=decode_prefix4(ndo, tptr, tlv_tlen, buf, sizeof(buf)); 359 if (i == -2) 360 goto trunc; 361 if (i == -3) 362 ND_PRINT(": IPv4 prefix (goes past end of TLV)"); 363 else if (i == -1) 364 ND_PRINT(": IPv4 prefix (invalid length)"); 365 else 366 ND_PRINT(": IPv4 prefix %s", buf); 367 } 368 else if (af == AFNUM_INET6) { 369 i=decode_prefix6(ndo, tptr, tlv_tlen, buf, sizeof(buf)); 370 if (i == -2) 371 goto trunc; 372 if (i == -3) 373 ND_PRINT(": IPv4 prefix (goes past end of TLV)"); 374 else if (i == -1) 375 ND_PRINT(": IPv6 prefix (invalid length)"); 376 else 377 ND_PRINT(": IPv6 prefix %s", buf); 378 } 379 else 380 ND_PRINT(": Address family %u prefix", af); 381 break; 382 case LDP_FEC_HOSTADDRESS: 383 break; 384 case LDP_FEC_MARTINI_VC: 385 /* 386 * We assume the type was supposed to be one of the MPLS 387 * Pseudowire Types. 388 */ 389 TLV_TCHECK(7); 390 vc_info_len = GET_U_1(tptr + 2); 391 392 /* 393 * According to RFC 4908, the VC info Length field can be zero, 394 * in which case not only are there no interface parameters, 395 * there's no VC ID. 396 */ 397 if (vc_info_len == 0) { 398 ND_PRINT(": %s, %scontrol word, group-ID %u, VC-info-length: %u", 399 tok2str(mpls_pw_types_values, "Unknown", GET_BE_U_2(tptr)&0x7fff), 400 GET_BE_U_2(tptr)&0x8000 ? "" : "no ", 401 GET_BE_U_4(tptr + 3), 402 vc_info_len); 403 break; 404 } 405 406 /* Make sure we have the VC ID as well */ 407 TLV_TCHECK(11); 408 ND_PRINT(": %s, %scontrol word, group-ID %u, VC-ID %u, VC-info-length: %u", 409 tok2str(mpls_pw_types_values, "Unknown", GET_BE_U_2(tptr)&0x7fff), 410 GET_BE_U_2(tptr)&0x8000 ? "" : "no ", 411 GET_BE_U_4(tptr + 3), 412 GET_BE_U_4(tptr + 7), 413 vc_info_len); 414 if (vc_info_len < 4) { 415 /* minimum 4, for the VC ID */ 416 ND_PRINT(" (invalid, < 4"); 417 return(tlv_len+4); /* Type & Length fields not included */ 418 } 419 vc_info_len -= 4; /* subtract out the VC ID, giving the length of the interface parameters */ 420 421 /* Skip past the fixed information and the VC ID */ 422 tptr+=11; 423 tlv_tlen-=11; 424 TLV_TCHECK(vc_info_len); 425 426 while (vc_info_len > 2) { 427 vc_info_tlv_type = GET_U_1(tptr); 428 vc_info_tlv_len = GET_U_1(tptr + 1); 429 if (vc_info_tlv_len < 2) 430 break; 431 if (vc_info_len < vc_info_tlv_len) 432 break; 433 434 ND_PRINT("\n\t\tInterface Parameter: %s (0x%02x), len %u", 435 tok2str(ldp_fec_martini_ifparm_values,"Unknown",vc_info_tlv_type), 436 vc_info_tlv_type, 437 vc_info_tlv_len); 438 439 switch(vc_info_tlv_type) { 440 case LDP_FEC_MARTINI_IFPARM_MTU: 441 ND_PRINT(": %u", GET_BE_U_2(tptr + 2)); 442 break; 443 444 case LDP_FEC_MARTINI_IFPARM_DESC: 445 ND_PRINT(": "); 446 for (idx = 2; idx < vc_info_tlv_len; idx++) 447 fn_print_char(ndo, GET_U_1(tptr + idx)); 448 break; 449 450 case LDP_FEC_MARTINI_IFPARM_VCCV: 451 ND_PRINT("\n\t\t Control Channels (0x%02x) = [%s]", 452 GET_U_1((tptr + 2)), 453 bittok2str(ldp_fec_martini_ifparm_vccv_cc_values, "none", GET_U_1((tptr + 2)))); 454 ND_PRINT("\n\t\t CV Types (0x%02x) = [%s]", 455 GET_U_1((tptr + 3)), 456 bittok2str(ldp_fec_martini_ifparm_vccv_cv_values, "none", GET_U_1((tptr + 3)))); 457 break; 458 459 default: 460 print_unknown_data(ndo, tptr+2, "\n\t\t ", vc_info_tlv_len-2); 461 break; 462 } 463 464 vc_info_len -= vc_info_tlv_len; 465 tptr += vc_info_tlv_len; 466 } 467 break; 468 } 469 470 break; 471 472 case LDP_TLV_GENERIC_LABEL: 473 TLV_TCHECK(4); 474 ND_PRINT("\n\t Label: %u", GET_BE_U_4(tptr) & 0xfffff); 475 break; 476 477 case LDP_TLV_STATUS: 478 TLV_TCHECK(8); 479 ui = GET_BE_U_4(tptr); 480 tptr+=4; 481 ND_PRINT("\n\t Status: 0x%02x, Flags: [%s and %s forward]", 482 ui&0x3fffffff, 483 ui&0x80000000 ? "Fatal error" : "Advisory Notification", 484 ui&0x40000000 ? "do" : "don't"); 485 ui = GET_BE_U_4(tptr); 486 tptr+=4; 487 if (ui) 488 ND_PRINT(", causing Message ID: 0x%08x", ui); 489 break; 490 491 case LDP_TLV_FT_SESSION: 492 TLV_TCHECK(12); 493 ft_flags = GET_BE_U_2(tptr); 494 ND_PRINT("\n\t Flags: [%sReconnect, %sSave State, %sAll-Label Protection, %s Checkpoint, %sRe-Learn State]", 495 ft_flags&0x8000 ? "" : "No ", 496 ft_flags&0x8 ? "" : "Don't ", 497 ft_flags&0x4 ? "" : "No ", 498 ft_flags&0x2 ? "Sequence Numbered Label" : "All Labels", 499 ft_flags&0x1 ? "" : "Don't "); 500 /* 16 bits (FT Flags) + 16 bits (Reserved) */ 501 tptr+=4; 502 ui = GET_BE_U_4(tptr); 503 if (ui) 504 ND_PRINT(", Reconnect Timeout: %ums", ui); 505 tptr+=4; 506 ui = GET_BE_U_4(tptr); 507 if (ui) 508 ND_PRINT(", Recovery Time: %ums", ui); 509 break; 510 511 case LDP_TLV_MTU: 512 TLV_TCHECK(2); 513 ND_PRINT("\n\t MTU: %u", GET_BE_U_2(tptr)); 514 break; 515 516 517 /* 518 * FIXME those are the defined TLVs that lack a decoder 519 * you are welcome to contribute code ;-) 520 */ 521 522 case LDP_TLV_HOP_COUNT: 523 case LDP_TLV_PATH_VECTOR: 524 case LDP_TLV_ATM_LABEL: 525 case LDP_TLV_FR_LABEL: 526 case LDP_TLV_EXTD_STATUS: 527 case LDP_TLV_RETURNED_PDU: 528 case LDP_TLV_RETURNED_MSG: 529 case LDP_TLV_ATM_SESSION_PARM: 530 case LDP_TLV_FR_SESSION_PARM: 531 case LDP_TLV_LABEL_REQUEST_MSG_ID: 532 533 default: 534 if (ndo->ndo_vflag <= 1) 535 print_unknown_data(ndo, tptr, "\n\t ", tlv_tlen); 536 break; 537 } 538 return(tlv_len+4); /* Type & Length fields not included */ 539 540 trunc: 541 nd_trunc_longjmp(ndo); 542 543 invalid: 544 return(tlv_len+4); /* Type & Length fields not included */ 545 } 546 547 void 548 ldp_print(netdissect_options *ndo, 549 const u_char *pptr, u_int len) 550 { 551 u_int processed; 552 553 ndo->ndo_protocol = "ldp"; 554 while (len > (sizeof(struct ldp_common_header) + sizeof(struct ldp_msg_header))) { 555 processed = ldp_pdu_print(ndo, pptr); 556 if (processed == 0) 557 return; 558 if (len < processed) { 559 ND_PRINT(" [remaining length %u < %u]", len, processed); 560 nd_print_invalid(ndo); 561 break; 562 } 563 len -= processed; 564 pptr += processed; 565 } 566 } 567 568 static u_int 569 ldp_pdu_print(netdissect_options *ndo, 570 const u_char *pptr) 571 { 572 const struct ldp_common_header *ldp_com_header; 573 const struct ldp_msg_header *ldp_msg_header; 574 const u_char *tptr,*msg_tptr; 575 u_short tlen; 576 u_short pdu_len,msg_len,msg_type; 577 u_int msg_tlen; 578 int hexdump,processed; 579 580 ldp_com_header = (const struct ldp_common_header *)pptr; 581 ND_TCHECK_SIZE(ldp_com_header); 582 583 /* 584 * Sanity checking of the header. 585 */ 586 if (GET_BE_U_2(ldp_com_header->version) != LDP_VERSION) { 587 ND_PRINT("%sLDP version %u packet not supported", 588 (ndo->ndo_vflag < 1) ? "" : "\n\t", 589 GET_BE_U_2(ldp_com_header->version)); 590 return 0; 591 } 592 593 pdu_len = GET_BE_U_2(ldp_com_header->pdu_length); 594 if (pdu_len < sizeof(struct ldp_common_header)-4) { 595 /* length too short */ 596 ND_PRINT("%sLDP, pdu-length: %u (too short, < %zu)", 597 (ndo->ndo_vflag < 1) ? "" : "\n\t", 598 pdu_len, 599 sizeof(struct ldp_common_header)-4); 600 return 0; 601 } 602 603 /* print the LSR-ID, label-space & length */ 604 ND_PRINT("%sLDP, Label-Space-ID: %s:%u, pdu-length: %u", 605 (ndo->ndo_vflag < 1) ? "" : "\n\t", 606 GET_IPADDR_STRING(ldp_com_header->lsr_id), 607 GET_BE_U_2(ldp_com_header->label_space), 608 pdu_len); 609 610 /* bail out if non-verbose */ 611 if (ndo->ndo_vflag < 1) 612 return 0; 613 614 /* ok they seem to want to know everything - lets fully decode it */ 615 tptr = pptr + sizeof(struct ldp_common_header); 616 tlen = pdu_len - (sizeof(struct ldp_common_header)-4); /* Type & Length fields not included */ 617 618 while(tlen>0) { 619 /* did we capture enough for fully decoding the msg header ? */ 620 ND_TCHECK_LEN(tptr, sizeof(struct ldp_msg_header)); 621 622 ldp_msg_header = (const struct ldp_msg_header *)tptr; 623 msg_len=GET_BE_U_2(ldp_msg_header->length); 624 msg_type=LDP_MASK_MSG_TYPE(GET_BE_U_2(ldp_msg_header->type)); 625 626 if (msg_len < sizeof(struct ldp_msg_header)-4) { 627 /* length too short */ 628 /* FIXME vendor private / experimental check */ 629 ND_PRINT("\n\t %s Message (0x%04x), length: %u (too short, < %zu)", 630 tok2str(ldp_msg_values, 631 "Unknown", 632 msg_type), 633 msg_type, 634 msg_len, 635 sizeof(struct ldp_msg_header)-4); 636 return 0; 637 } 638 639 /* FIXME vendor private / experimental check */ 640 ND_PRINT("\n\t %s Message (0x%04x), length: %u, Message ID: 0x%08x, Flags: [%s if unknown]", 641 tok2str(ldp_msg_values, 642 "Unknown", 643 msg_type), 644 msg_type, 645 msg_len, 646 GET_BE_U_4(ldp_msg_header->id), 647 LDP_MASK_U_BIT(GET_BE_U_2(ldp_msg_header->type)) ? "continue processing" : "ignore"); 648 649 msg_tptr=tptr+sizeof(struct ldp_msg_header); 650 msg_tlen=msg_len-(sizeof(struct ldp_msg_header)-4); /* Type & Length fields not included */ 651 652 /* did we capture enough for fully decoding the message ? */ 653 ND_TCHECK_LEN(tptr, msg_len); 654 hexdump=FALSE; 655 656 switch(msg_type) { 657 658 case LDP_MSG_NOTIF: 659 case LDP_MSG_HELLO: 660 case LDP_MSG_INIT: 661 case LDP_MSG_KEEPALIVE: 662 case LDP_MSG_ADDRESS: 663 case LDP_MSG_LABEL_MAPPING: 664 case LDP_MSG_ADDRESS_WITHDRAW: 665 case LDP_MSG_LABEL_WITHDRAW: 666 while(msg_tlen >= 4) { 667 processed = ldp_tlv_print(ndo, msg_tptr, msg_tlen); 668 if (processed == 0) 669 break; 670 msg_tlen-=processed; 671 msg_tptr+=processed; 672 } 673 break; 674 675 /* 676 * FIXME those are the defined messages that lack a decoder 677 * you are welcome to contribute code ;-) 678 */ 679 680 case LDP_MSG_LABEL_REQUEST: 681 case LDP_MSG_LABEL_RELEASE: 682 case LDP_MSG_LABEL_ABORT_REQUEST: 683 684 default: 685 if (ndo->ndo_vflag <= 1) 686 print_unknown_data(ndo, msg_tptr, "\n\t ", msg_tlen); 687 break; 688 } 689 /* do we want to see an additionally hexdump ? */ 690 if (ndo->ndo_vflag > 1 || hexdump==TRUE) 691 print_unknown_data(ndo, tptr+sizeof(struct ldp_msg_header), "\n\t ", 692 msg_len); 693 694 tptr += msg_len+4; 695 tlen -= msg_len+4; 696 } 697 return pdu_len+4; 698 trunc: 699 nd_trunc_longjmp(ndo); 700 } 701