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