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