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