diff options
author | Guy Harris <guy@alum.mit.edu> | 2002-01-21 22:15:18 +0000 |
---|---|---|
committer | Guy Harris <guy@alum.mit.edu> | 2002-01-21 22:15:18 +0000 |
commit | 6deb504cff5b169cbfcdc6e58e99481b59d5bf1f (patch) | |
tree | 4dcb310176b96f64d83ba42e9f062f6b14691fd8 /packet-ldp.c | |
parent | c2945fe39f2afc671ac54291c87fb3ee2f3155b6 (diff) |
From Ricardo Barroetave�a: support for all TLVs and messages in RFC
3036.
svn path=/trunk/; revision=4590
Diffstat (limited to 'packet-ldp.c')
-rw-r--r-- | packet-ldp.c | 1853 |
1 files changed, 1327 insertions, 526 deletions
diff --git a/packet-ldp.c b/packet-ldp.c index ac5ed43d8c..bda07e5c04 100644 --- a/packet-ldp.c +++ b/packet-ldp.c @@ -1,7 +1,7 @@ /* packet-ldp.c * Routines for LDP (RFC 3036) packet disassembly * - * $Id: packet-ldp.c,v 1.26 2002/01/21 07:36:36 guy Exp $ + * $Id: packet-ldp.c,v 1.27 2002/01/21 22:15:17 guy Exp $ * * Copyright (c) November 2000 by Richard Sharpe <rsharpe@ns.aus.com> * @@ -61,22 +61,76 @@ static int hf_ldp_version = -1; static int hf_ldp_pdu_len = -1; static int hf_ldp_lsr = -1; static int hf_ldp_ls_id = -1; +static int hf_ldp_msg_ubit = -1; static int hf_ldp_msg_type = -1; static int hf_ldp_msg_len = -1; static int hf_ldp_msg_id = -1; +static int hf_ldp_msg_vendor_id = -1; +static int hf_ldp_msg_experiment_id = -1; static int hf_ldp_tlv_value = -1; static int hf_ldp_tlv_type = -1; +static int hf_ldp_tlv_unknown = -1; static int hf_ldp_tlv_len = -1; static int hf_ldp_tlv_val_hold = -1; static int hf_ldp_tlv_val_target = -1; static int hf_ldp_tlv_val_request = -1; static int hf_ldp_tlv_val_res = -1; +static int hf_ldp_tlv_ipv4_taddr = -1; static int hf_ldp_tlv_config_seqno = -1; +static int hf_ldp_tlv_ipv6_taddr = -1; static int hf_ldp_tlv_fec_wc = -1; static int hf_ldp_tlv_fec_af = -1; static int hf_ldp_tlv_fec_len = -1; static int hf_ldp_tlv_fec_pfval = -1; +static int hf_ldp_tlv_fec_hoval = -1; +static int hf_ldp_tlv_addrl_addr_family = -1; +static int hf_ldp_tlv_addrl_addr = -1; +static int hf_ldp_tlv_hc_value = -1; +static int hf_ldp_tlv_pv_lsrid = -1; static int hf_ldp_tlv_generic_label = -1; +static int hf_ldp_tlv_atm_label_vbits = -1; +static int hf_ldp_tlv_atm_label_vpi = -1; +static int hf_ldp_tlv_atm_label_vci = -1; +static int hf_ldp_tlv_fr_label_len = -1; +static int hf_ldp_tlv_fr_label_dlci = -1; +static int hf_ldp_tlv_status_ebit = -1; +static int hf_ldp_tlv_status_fbit = -1; +static int hf_ldp_tlv_status_data = -1; +static int hf_ldp_tlv_status_msg_id = -1; +static int hf_ldp_tlv_status_msg_type = -1; +static int hf_ldp_tlv_extstatus_data = -1; +static int hf_ldp_tlv_returned_version = -1; +static int hf_ldp_tlv_returned_pdu_len = -1; +static int hf_ldp_tlv_returned_lsr = -1; +static int hf_ldp_tlv_returned_ls_id = -1; +static int hf_ldp_tlv_returned_msg_ubit = -1; +static int hf_ldp_tlv_returned_msg_type = -1; +static int hf_ldp_tlv_returned_msg_len = -1; +static int hf_ldp_tlv_returned_msg_id = -1; +static int hf_ldp_tlv_sess_ver = -1; +static int hf_ldp_tlv_sess_ka = -1; +static int hf_ldp_tlv_sess_advbit = -1; +static int hf_ldp_tlv_sess_ldetbit = -1; +static int hf_ldp_tlv_sess_pvlim = -1; +static int hf_ldp_tlv_sess_mxpdu = -1; +static int hf_ldp_tlv_sess_rxlsr = -1; +static int hf_ldp_tlv_sess_rxls = -1; +static int hf_ldp_tlv_sess_atm_merge = -1; +static int hf_ldp_tlv_sess_atm_lr = -1; +static int hf_ldp_tlv_sess_atm_dir = -1; +static int hf_ldp_tlv_sess_atm_minvpi = -1; +static int hf_ldp_tlv_sess_atm_maxvpi = -1; +static int hf_ldp_tlv_sess_atm_minvci = -1; +static int hf_ldp_tlv_sess_atm_maxvci = -1; +static int hf_ldp_tlv_sess_fr_merge = -1; +static int hf_ldp_tlv_sess_fr_lr = -1; +static int hf_ldp_tlv_sess_fr_dir = -1; +static int hf_ldp_tlv_sess_fr_len = -1; +static int hf_ldp_tlv_sess_fr_mindlci = -1; +static int hf_ldp_tlv_sess_fr_maxdlci = -1; +static int hf_ldp_tlv_lbl_req_msg_id = -1; +static int hf_ldp_tlv_vendor_id = -1; +static int hf_ldp_tlv_experiment_id = -1; static int ett_ldp = -1; static int ett_ldp_header = -1; @@ -89,6 +143,9 @@ static int ett_ldp_fec = -1; static int tcp_port = 0; static int udp_port = 0; +/* desegmentation of LDP over TCP */ +static gboolean ldp_desegment = FALSE; + /* Add your functions here */ static int global_ldp_tcp_port = TCP_PORT_LDP; @@ -119,29 +176,32 @@ static int global_ldp_udp_port = UDP_PORT_LDP; #define TLV_LABEL_REQUEST_MESSAGE_ID 0x0600 #define TLV_VENDOR_PRIVATE_START 0x3E00 -#define TLV_VENDOR_PROVATE_END 0x3EFF +#define TLV_VENDOR_PRIVATE_END 0x3EFF #define TLV_EXPERIMENTAL_START 0x3F00 #define TLV_EXPERIMENTAL_END 0x3FFF static const value_string tlv_type_names[] = { - { TLV_FEC, "Forwarding Equivalence Classes" }, - { TLV_ADDRESS_LIST, "Address List"}, - { TLV_HOP_COUNT, "Hop Count"}, - { TLV_PATH_VECTOR, "Path Vector"}, - { TLV_GENERIC_LABEL, "Generic Label"}, - { TLV_ATM_LABEL, "Frame Label"}, - { TLV_STATUS, "Status"}, - { TLV_EXTENDED_STATUS, "Extended Status"}, - { TLV_RETURNED_PDU, "Returned PDU"}, - { TLV_RETURNED_MESSAGE, "Returned Message"}, - { TLV_COMMON_HELLO_PARMS, "Common Hello Parameters"}, - { TLV_IPV4_TRANSPORT_ADDRESS, "IPv4 Transport Address"}, - { TLV_CONFIGURATION_SEQNO, "Configuration Sequence Number"}, - { TLV_IPV6_TRANSPORT_ADDRESS, "IPv6 Transport Address"}, - { TLV_COMMON_SESSION_PARMS, "Common Session Parameters"}, - { TLV_ATM_SESSION_PARMS, "ATM Session Parameters"}, - { TLV_FRAME_RELAY_SESSION_PARMS, "Frame Relay Session Parameters"}, - { TLV_LABEL_REQUEST_MESSAGE_ID, "Label Request Message ID"}, + { TLV_FEC, "Forwarding Equivalence Classes TLV" }, + { TLV_ADDRESS_LIST, "Address List TLV"}, + { TLV_HOP_COUNT, "Hop Count TLV"}, + { TLV_PATH_VECTOR, "Path Vector TLV"}, + { TLV_GENERIC_LABEL, "Generic Label TLV"}, + { TLV_ATM_LABEL, "ATM Label TLV"}, + { TLV_FRAME_LABEL, "Frame Label TLV"}, + { TLV_STATUS, "Status TLV"}, + { TLV_EXTENDED_STATUS, "Extended Status TLV"}, + { TLV_RETURNED_PDU, "Returned PDU TLV"}, + { TLV_RETURNED_MESSAGE, "Returned Message TLV"}, + { TLV_COMMON_HELLO_PARMS, "Common Hello Parameters TLV"}, + { TLV_IPV4_TRANSPORT_ADDRESS, "IPv4 Transport Address TLV"}, + { TLV_CONFIGURATION_SEQNO, "Configuration Sequence Number TLV"}, + { TLV_IPV6_TRANSPORT_ADDRESS, "IPv6 Transport Address TLV"}, + { TLV_COMMON_SESSION_PARMS, "Common Session Parameters TLV"}, + { TLV_ATM_SESSION_PARMS, "ATM Session Parameters TLV"}, + { TLV_FRAME_RELAY_SESSION_PARMS, "Frame Relay Session Parameters TLV"}, + { TLV_LABEL_REQUEST_MESSAGE_ID, "Label Request Message ID TLV"}, + { TLV_VENDOR_PRIVATE_START, "Vendor Private TLV"}, + { TLV_EXPERIMENTAL_START, "Experimental TLV"}, { 0, NULL} }; @@ -166,685 +226,1422 @@ static const value_string tlv_type_names[] = { #define LDP_EXPERIMENTAL_MESSAGE_END 0x3FFF static const value_string ldp_message_types[] = { - {LDP_NOTIFICATION, "Notification"}, - {LDP_HELLO, "Hello"}, - {LDP_INITIALIZATION, "Initialization"}, - {LDP_KEEPALIVE, "Keep Alive"}, - {LDP_ADDRESS, "Address"}, - {LDP_ADDRESS_WITHDRAWAL, "Address Withdrawal"}, - {LDP_LABEL_MAPPING, "Label Mapping"}, - {LDP_LABEL_REQUEST, "Label Request"}, - {LDP_LABEL_WITHDRAWAL, "Label Withdrawal"}, - {LDP_LABEL_RELEASE, "Label Release"}, - {LDP_LABEL_ABORT_REQUEST, "Label Abort Request"}, + {LDP_NOTIFICATION, "Notification Message"}, + {LDP_HELLO, "Hello Message"}, + {LDP_INITIALIZATION, "Initialization Message"}, + {LDP_KEEPALIVE, "Keep Alive Message"}, + {LDP_ADDRESS, "Address Message"}, + {LDP_ADDRESS_WITHDRAWAL, "Address Withdrawal Message"}, + {LDP_LABEL_MAPPING, "Label Mapping Message"}, + {LDP_LABEL_REQUEST, "Label Request Message"}, + {LDP_LABEL_WITHDRAWAL, "Label Withdrawal Message"}, + {LDP_LABEL_RELEASE, "Label Release Message"}, + {LDP_LABEL_ABORT_REQUEST, "Label Abort Request Message"}, + {LDP_VENDOR_PRIVATE_START, "Vendor-Private Message"}, + {LDP_EXPERIMENTAL_MESSAGE_START, "Experimental Message"}, {0, NULL} }; +static const true_false_string ldp_message_ubit = { + "Unknown bit set", + "Unknown bit not set" +}; + static const true_false_string hello_targeted_vals = { "Targeted Hello", "Link Hello" }; -static const value_string fec_types[] = { - {1, "Wildcard FEC"}, - {2, "Prefix FEC"}, - {3, "Host Address FEC"}, +static const value_string tlv_unknown_vals[] = { + {0, "Known TLV"}, + {1, "Known TLV"}, + {2, "Unknown TLV, do not Forward"}, + {3, "Unknown TLV, do Forward"}, {0, NULL} }; -static const true_false_string hello_requested_vals = { - "Source requests periodic hellos", - "Source does not request periodic hellos" -}; - -/* Dissect the common hello params */ - -void dissect_tlv_common_hello_parms(tvbuff_t *tvb, guint offset, proto_tree *tree, int rem) -{ - proto_tree *ti = NULL, *val_tree = NULL; - - if (tree) { - - ti = proto_tree_add_item(tree, hf_ldp_tlv_value, tvb, offset, rem, - FALSE); - - val_tree = proto_item_add_subtree(ti, ett_ldp_tlv_val); - - proto_tree_add_item(val_tree, hf_ldp_tlv_val_hold, tvb, offset, 2, FALSE); - - proto_tree_add_boolean(val_tree, hf_ldp_tlv_val_target, tvb, offset + 2, 2, FALSE); - proto_tree_add_boolean(val_tree, hf_ldp_tlv_val_request, tvb, offset + 2, 2, FALSE); - proto_tree_add_item(val_tree, hf_ldp_tlv_val_res, tvb, offset + 2, 2, FALSE); - } - -} - -/* Dissect a TLV and return the number of bytes consumed ... */ - -int dissect_tlv(tvbuff_t *tvb, guint offset, proto_tree *tree, int rem) -{ - guint16 message = tvb_get_ntohs(tvb, offset), - length = tvb_get_ntohs(tvb, offset + 2), - pad = 0, fec_len = 0; - proto_tree *ti = NULL, *tlv_tree = NULL; - - /* Hmmm, check for illegal alignment padding */ - - if (message == 0x00) { - - proto_tree_add_text(tree, tvb, offset, 2, "Illegal Padding: %04X", message); - offset += 2; pad = 2; - message = tvb_get_ntohs(tvb, offset); - length = tvb_get_ntohs(tvb, offset + 2); - - } - - length = MIN(length, rem); /* Don't go haywire if a problem ... */ - - if (tree) { - - /* FIXME: Account for vendor and special messages */ - - ti = proto_tree_add_text(tree, tvb, offset, length + 4, "%s", - val_to_str(message, tlv_type_names, "Unknown TLV type (0x%04X)")); - - tlv_tree = proto_item_add_subtree(ti, ett_ldp_tlv); - - proto_tree_add_item(tlv_tree, hf_ldp_tlv_type, tvb, offset, 2, FALSE); - - proto_tree_add_item(tlv_tree, hf_ldp_tlv_len, tvb, offset + 2, 2, FALSE); - - switch (message) { - - case TLV_FEC: /* Process an FEC */ - - offset += 4; /* Skip the TLV header */ - - fec_len = length; +#define WILDCARD_FEC 1 +#define PREFIX_FEC 2 +#define HOST_FEC 3 - while (fec_len > 0) { - proto_tree *fec_tree = NULL; - guint prefix_len_octets, prefix_len, prefix; - - - switch (tvb_get_guint8(tvb, offset)) { - case 1: /* Wild Card */ - - proto_tree_add_item(tlv_tree, hf_ldp_tlv_fec_wc, tvb, offset, 4, FALSE); - fec_len -= 4; - - offset += 4; - - break; - - case 2: /* Prefix */ - - /* Add a subtree for this ... */ - - ti = proto_tree_add_text(tlv_tree, tvb, offset, 8, "Prefix FEC Element"); - - fec_tree = proto_item_add_subtree(ti, ett_ldp_fec); - - proto_tree_add_item(fec_tree, hf_ldp_tlv_fec_wc, tvb, offset, 1, FALSE); - - offset += 1; - - /* XXX - the address family length should be extracted and used to - dissect the prefix field. */ - proto_tree_add_item(fec_tree, hf_ldp_tlv_fec_af, tvb, offset, 2, FALSE); - offset += 2; +static const value_string fec_types[] = { + {WILDCARD_FEC, "Wildcard FEC"}, + {PREFIX_FEC, "Prefix FEC"}, + {HOST_FEC, "Host Address FEC"}, + {0, NULL} +}; - prefix_len = tvb_get_guint8(tvb, offset); - proto_tree_add_item(fec_tree, hf_ldp_tlv_fec_len, tvb, offset, 1, FALSE); +static const value_string tlv_atm_merge_vals[] = { + {0, "Merge not supported"}, + {1, "VP merge supported"}, + {2, "VC merge supported"}, + {3, "VP & VC merge supported"}, + {0, NULL} +}; - offset += 1; - /* This is IPv4 specific. Should do IPv6 according to AF*/ - prefix_len_octets = MIN( (prefix_len+7)/8 , 4 ); - if (prefix_len > 32) { - proto_tree_add_text(fec_tree, tvb, offset, 0, - "Invalid prefix %u length, guessing 32", prefix_len); - prefix_len_octets = 4; - } - switch (prefix_len_octets){ - case (0): /*prefix_length=0*/ - prefix = 0; - break; - case (1): /*1<=prefix_length<=8*/ - prefix = tvb_get_guint8(tvb, offset); - break; - case (2): /*9<=prefix_length<=16*/ - prefix = tvb_get_letohs(tvb, offset); - break; - case (3): /*17<=prefix_length<=24*/ - prefix = tvb_get_letoh24(tvb, offset); - break; - case (4): /*25<=prefix_length<=32*/ - prefix = tvb_get_letohl(tvb, offset); - break; - default: /*prefix_length>32*/ - g_assert_not_reached(); - prefix = 0; - break; - } - proto_tree_add_ipv4(fec_tree, hf_ldp_tlv_fec_pfval, tvb, - offset, prefix_len_octets, prefix); - fec_len -= 4+prefix_len_octets; - break; +static const value_string tlv_atm_vbits_vals[] = { + {0, "VPI & VCI Significant"}, + {1, "Only VPI Significant"}, + {2, "Only VCI Significant"}, + {3, "VPI & VCI not Significant, nonsense"}, + {0, NULL} +}; - case 3: /* Host address */ +static const value_string tlv_fr_merge_vals[] = { + {0, "Merge not supported"}, + {1, "Merge supported"}, + {2, "Unspecified"}, + {3, "Unspecified"}, + {0, NULL} +}; - /* XXX - write me. */ +static const value_string tlv_fr_len_vals[] = { + {0, "10 bits"}, + {1, "Reserved"}, + {2, "23 bits"}, + {3, "Reserved"}, + {0, NULL} +}; - fec_len -= 8; +static const true_false_string tlv_atm_dirbit = { + "Bidirectional capability", + "Unidirectional capability" +}; - offset += 8; +static const true_false_string hello_requested_vals = { + "Source requests periodic hellos", + "Source does not request periodic hellos" +}; - break; +static const true_false_string tlv_sess_advbit_vals = { + "Downstream On Demand proposed", + "Downstream Unsolicited proposed" +}; - default: /* Unknown */ +static const true_false_string tlv_sess_ldetbit_vals = { + "Loop Detection Enabled", + "Loop Detection Disabled" +}; - /* XXX - do all FEC's have a length that's a multiple of 4? */ - /* Hmmm, don't think so. Will check. RJS. */ +static const true_false_string tlv_status_ebit = { + "Fatal Error Notification", + "Advisory Notification" +}; - fec_len -= 4; +static const true_false_string tlv_status_fbit = { + "Notification should be Forwarded", + "Notification should NOT be Forwarded" +}; - offset += 4; +static const value_string tlv_status_data[] = { + {0, "Success"}, + {1, "Bad LDP Identifier"}, + {2, "Bad Protocol Version"}, + {3, "Bad PDU Length"}, + {4, "Unknown Message Type"}, + {5, "Bad Message Length"}, + {6, "Unknown TLV"}, + {7, "Bad TLV Length"}, + {8, "Malformed TLV Value"}, + {9, "Hold Timer Expired"}, + {10, "Shutdown"}, + {11, "Loop Detected"}, + {12, "Unknown FEC"}, + {13, "No Route"}, + {14, "No Label Resources"}, + {15, "Label Resources / Available"}, + {16, "Session Rejected / No Hello"}, + {17, "Session Rejected / Parameters Advertisement Mode"}, + {18, "Session Rejected / Parameters Max PDU Length"}, + {19, "Session Rejected / Parameters Label Range"}, + {20, "KeepAlive Timer Expired"}, + {21, "Label Request Aborted"}, + {22, "Missing Message Parameters"}, + {23, "Unsoported Address Family"}, + {24, "Session Rejected / Bad KeepAlive Time"}, + {25, "Internal Error"}, + {0, NULL} +}; - break; +/* Dissect FEC TLV */ +void +dissect_tlv_fec(tvbuff_t *tvb, guint offset, proto_tree *tree, int rem) +{ + proto_tree *ti=NULL, *val_tree=NULL, *fec_tree=NULL; + guint16 family, ix=1, ax; + guint8 addr_size=0, *addr, implemented, prefix_len_octets, prefix_len, host_len; + void *str_handler=NULL; + char *str; + + if (tree) { + + if( rem < 4 ) { + proto_tree_add_text(tree, tvb, offset, rem, "Error processing TLV"); + return; + } + + ti=proto_tree_add_text(tree, tvb, offset, rem, "FEC Elements"); + val_tree=proto_item_add_subtree(ti, ett_ldp_tlv_val); + if(val_tree == NULL) return; + + while (rem > 0){ + switch (tvb_get_guint8(tvb, offset)) { + case WILDCARD_FEC: + ti = proto_tree_add_text(val_tree, tvb, offset, 4, "FEC Element %u", ix); + fec_tree = proto_item_add_subtree(ti, ett_ldp_fec); + if(fec_tree == NULL) return; + proto_tree_add_item(fec_tree, hf_ldp_tlv_fec_wc,tvb, offset, 4, FALSE); + rem -= 1; + offset += 1; + break; + + case PREFIX_FEC: + if( rem < 4 ){/*not enough*/ + proto_tree_add_text(val_tree, tvb, offset, rem, "Error in FEC Element %u", ix); + return; + } + family=tvb_get_ntohs(tvb, offset+1); + prefix_len=tvb_get_guint8(tvb, offset+3); + prefix_len_octets=(prefix_len+7)/8; + + implemented=1; + switch(family) { + case AFNUM_INET: /*IPv4*/ + addr_size=4; + str_handler=ip_to_str; + break; + case AFNUM_INET6: /*IPv6*/ + addr_size=16; + str_handler=ip6_to_str; + break; + default: + implemented=0; + break; + } + + if( !implemented ) { + guint16 noctets; + + noctets= rem>4+prefix_len_octets?4+prefix_len_octets:rem; + proto_tree_add_text(val_tree, tvb, offset, noctets,"Support for Address Family not implemented"); + offset+=noctets; + rem-=noctets; + break; + } + + if( rem < 4+MIN(addr_size, prefix_len_octets) ){ + proto_tree_add_text(val_tree, tvb, offset, rem, "Error in FEC Element %u", ix); + return; + } + + /*Add a subtree for this*/ + ti = proto_tree_add_text(val_tree, tvb, offset, 4+MIN(addr_size, prefix_len_octets), "FEC Element %u", ix); + fec_tree = proto_item_add_subtree(ti, ett_ldp_fec); + if(fec_tree == NULL) return; + proto_tree_add_item(fec_tree, hf_ldp_tlv_fec_wc, tvb, offset, 1, FALSE); + offset += 1; + + proto_tree_add_item(fec_tree, hf_ldp_tlv_fec_af, tvb, offset, 2, FALSE); + offset += 2; + + proto_tree_add_item(fec_tree, hf_ldp_tlv_fec_len, tvb, offset, 1, FALSE); + offset += 1; + + + if( addr_size < prefix_len_octets) { + offset+=addr_size; + rem-=addr_size; + proto_tree_add_text(fec_tree, tvb, offset-1, 1, "Invalid prefix %u length for family %s", prefix_len, val_to_str(family, afn_vals, "Unknown Family")); + break; + } + + if( (addr=g_malloc0(addr_size)) == NULL ){ + /*big big trouble, no mem or bad addr_size*/ + fprintf(stderr, "packet-ldp: dissect_tlv_fec() malloc failed\n"); + return; + } + + for(ax=0; ax+1 <= prefix_len_octets; ax++) + addr[ax]=tvb_get_guint8(tvb, offset+ax); + if( prefix_len % 8 ) + addr[ax-1] = addr[ax-1]&(0xFF<<(8-prefix_len%8)); + + str = (* (char* (*)(guint8 *))str_handler)(addr); + proto_tree_add_string_format(fec_tree, hf_ldp_tlv_fec_pfval, tvb, offset, prefix_len_octets, str, "Prefix: %s", str); + + offset += prefix_len_octets; + rem -= 4+prefix_len_octets; + g_free(addr); + break; + + case HOST_FEC: + if( rem < 4 ){/*not enough*/ + proto_tree_add_text(val_tree, tvb, offset, rem, "Error in FEC Element %u", ix); + return; + } + family=tvb_get_ntohs(tvb, offset+1); + host_len=tvb_get_guint8(tvb, offset+3); + + implemented=1; + switch(family) { + case AFNUM_INET: /*IPv4*/ + addr_size=4; + str_handler=ip_to_str; + break; + case AFNUM_INET6: /*IPv6*/ + addr_size=16; + str_handler=ip6_to_str; + break; + default: + implemented=0; + break; + } + + if( !implemented ) { + guint16 noctets; + + noctets= rem>4+host_len?4+host_len:rem; + proto_tree_add_text(val_tree, tvb, offset, noctets,"Support for Address Family not implemented"); + offset+=noctets; + rem-=noctets; + break; + } + + if( rem < 4+addr_size ){ + proto_tree_add_text(val_tree, tvb, offset, rem, "Error in FEC Element %u", ix); + return; + } + + /*Add a subtree for this*/ + ti = proto_tree_add_text(val_tree, tvb, offset, 4+addr_size, "FEC Element %u", ix); + fec_tree = proto_item_add_subtree(ti, ett_ldp_fec); + if(fec_tree == NULL) return; + proto_tree_add_item(fec_tree, hf_ldp_tlv_fec_wc, tvb, offset, 1, FALSE); + offset += 1; + + proto_tree_add_item(fec_tree, hf_ldp_tlv_fec_af, tvb, offset, 2, FALSE); + offset += 2; + + proto_tree_add_item(fec_tree, hf_ldp_tlv_fec_len, tvb, offset, 1, FALSE); + offset += 1; + + + if( addr_size != host_len) { + offset+=addr_size; + rem-=addr_size; + proto_tree_add_text(fec_tree, tvb, offset-1, 1, "Invalid address length %u length for family %s", host_len, val_to_str(family, afn_vals, "Unknown Family")); + break; + } + + if( (addr=g_malloc0(addr_size)) == NULL ){ + /*big big xtrouble, no mem or bad addr_size*/ + fprintf(stderr, "packet-ldp: dissect_tlv_fec() malloc failed\n"); + return; + } + + for(ax=0; ax+1 <= host_len; ax++) + addr[ax]=tvb_get_guint8(tvb, offset+ax); + + str = (* (char* (*)(guint8 *))str_handler)(addr); + proto_tree_add_string_format(fec_tree, hf_ldp_tlv_fec_hoval, tvb, offset, host_len, str, "Address: %s", str); + + offset += host_len; + rem -= 4+host_len; + g_free(addr); + break; + + default: /* Unknown */ + /* XXX - do all FEC's have a length that's a multiple of 4? */ + /* Hmmm, don't think so. Will check. RJS. */ + /* If we don't know its structure, we have to exit */ + ti = proto_tree_add_text(val_tree, tvb, offset, 4, "FEC Element %u", ix); + fec_tree = proto_item_add_subtree(ti, ett_ldp_fec); + if(fec_tree == NULL) return; + proto_tree_add_text(fec_tree, tvb, offset, rem, "Unknown FEC TLV type"); + return; + } + ix++; + } } - - } - - break;; - - case TLV_GENERIC_LABEL: - - proto_tree_add_item(tlv_tree, hf_ldp_tlv_generic_label, tvb, offset + 4, 4, FALSE); - - break; - - case TLV_COMMON_HELLO_PARMS: - - dissect_tlv_common_hello_parms(tvb, offset + 4, tlv_tree, length); - break; - - case TLV_CONFIGURATION_SEQNO: - - proto_tree_add_item(tlv_tree, hf_ldp_tlv_config_seqno, tvb, offset + 4, 4, FALSE); - break; - - default: - proto_tree_add_item(tlv_tree, hf_ldp_tlv_value, tvb, offset + 4, - length, FALSE); - - break; - } - - } - - return length + pad + 4; /* Length of the value field + header */ - } -/* - * Each of these routines dissect the relevant messages, but the msg header - * has already been dissected. - */ +/* Dissect Address List TLV */ void -dissect_ldp_notification(tvbuff_t *tvb, guint offset, packet_info *pinfo, proto_tree *tree, guint length) +dissect_tlv_address_list(tvbuff_t *tvb, guint offset, proto_tree *tree, int rem) { - guint rem = length, cc = 0; - - while (rem > 0) { - - rem -= (cc = dissect_tlv(tvb, offset, tree, rem)); - offset += cc; - - } - + proto_tree *ti = NULL, *val_tree = NULL; + guint16 family, ix; + guint8 addr_size, *addr; + void *str_handler; + char *str; + + if (tree) { + if( rem < 2 ) { + proto_tree_add_text(tree, tvb, offset, rem, + "Error processing TLV"); + return; + } + + family=tvb_get_ntohs(tvb, offset); + proto_tree_add_item(tree, hf_ldp_tlv_addrl_addr_family, tvb, + offset, 2, FALSE); + switch(family) { + case AFNUM_INET: /*IPv4*/ + addr_size=4; + str_handler=ip_to_str; + break; + case AFNUM_INET6: /*IPv6*/ + addr_size=16; + str_handler=ip6_to_str; + break; + default: + proto_tree_add_text(tree, tvb, offset+2, rem-2, + "Support for Address Family not implemented"); + return; + } + + offset+=2; rem-=2; + ti=proto_tree_add_text(tree, tvb, offset, rem, "Addresses"); + val_tree=proto_item_add_subtree(ti, ett_ldp_tlv_val); + + if(val_tree == NULL) return; + if( (addr=g_malloc(addr_size)) == NULL ){ + /*big big trouble*/ + fprintf(stderr, "packet-ldp: dissect_tlv_address_list() malloc failed\n"); + return; + } + + for(ix=1; rem >= addr_size; ix++, offset += addr_size, + rem -= addr_size) { + if( (tvb_memcpy(tvb, addr, offset, addr_size)) + == NULL) + break; + + str = (* (char* (*)(guint8 *))str_handler)(addr); + proto_tree_add_string_format(val_tree, + hf_ldp_tlv_addrl_addr, tvb, offset, addr_size, str, + "Address %u : %s", ix, str); + } + if(rem) + proto_tree_add_text(val_tree, tvb, offset, rem, + "Error processing TLV"); + g_free(addr); + } } -/* Dissect a Hello Message ... */ -void -dissect_ldp_hello(tvbuff_t *tvb, guint offset, packet_info *pinfo, proto_tree *tree, guint length) -{ - guint rem = length, cc = 0; - - while (rem > 0) { - - rem -= (cc = dissect_tlv(tvb, offset, tree, rem)); - offset += cc; - - } - -} +/* Dissect Path Vector TLV */ void -dissect_ldp_initialization(tvbuff_t *tvb, guint offset, packet_info *pinfo, proto_tree *tree, guint length) +dissect_tlv_path_vector(tvbuff_t *tvb, guint offset, proto_tree *tree, int rem) { - guint rem = length, cc = 0; - - while (rem > 0) { - - rem -= (cc = dissect_tlv(tvb, offset, tree, rem)); - offset += cc; - - } - + proto_tree *ti = NULL, *val_tree = NULL; + guint8 ix, *addr; + + if (tree) { + ti=proto_tree_add_text(tree, tvb, offset, rem, "LSR IDs"); + val_tree=proto_item_add_subtree(ti, ett_ldp_tlv_val); + + if(val_tree == NULL) return; + + for(ix=1; rem >= 4; ix++, offset += 4, rem -= 4) { + if( (addr=(guint8 *)tvb_get_ptr(tvb, offset, 4)) + == NULL) + break; + proto_tree_add_ipv4_format(val_tree, hf_ldp_tlv_pv_lsrid, tvb, + offset, 4, tvb_get_ntohl(tvb, offset), "LSR Id %u : %s", ix, + ip_to_str(addr)); + } + if(rem) + proto_tree_add_text(val_tree, tvb, offset, rem, + "Error processing TLV"); + } } -void -dissect_ldp_keepalive(tvbuff_t *tvb, guint offset, packet_info *pinfo, proto_tree *tree, guint length) -{ - guint rem = length, cc = 0; - - while (rem > 0) { - - rem -= (cc = dissect_tlv(tvb, offset, tree, rem)); - offset += cc; - - } - -} +/* Dissect ATM Label TLV */ void -dissect_ldp_address(tvbuff_t *tvb, guint offset, packet_info *pinfo, proto_tree *tree, guint length) +dissect_tlv_atm_label(tvbuff_t *tvb, guint offset, proto_tree *tree, int rem) { - guint rem = length, cc = 0; - - while (rem > 0) { - - rem -= (cc = dissect_tlv(tvb, offset, tree, rem)); - offset += cc; - - } - + proto_tree *ti = NULL, *val_tree = NULL; + guint16 id; + + if(tree) { + if(rem != 4){ + proto_tree_add_text(tree, tvb, offset, rem, "Error processing TLV"); + return; + } + ti=proto_tree_add_text(tree, tvb, offset, rem, "ATM Label"); + val_tree=proto_item_add_subtree(ti, ett_ldp_tlv_val); + if(val_tree == NULL) return; + + proto_tree_add_item(val_tree, hf_ldp_tlv_atm_label_vbits, tvb, offset, 1, FALSE); + + id=tvb_get_ntohs(tvb, offset)&0x0FFF; + proto_tree_add_uint_format(val_tree, hf_ldp_tlv_atm_label_vpi, tvb, offset, 2, id, "VPI: %u", id); + + id=tvb_get_ntohs(tvb, offset+2); + proto_tree_add_uint_format(val_tree, hf_ldp_tlv_atm_label_vci, tvb, offset+2, 2, id, "VCI: %u", id); + } } -void -dissect_ldp_address_withdrawal(tvbuff_t *tvb, guint offset, packet_info *pinfo, proto_tree *tree, guint length) -{ - guint rem = length, cc = 0; - - while (rem > 0) { - - rem -= (cc = dissect_tlv(tvb, offset, tree, rem)); - offset += cc; - - } - -} +/* Dissect FRAME RELAY Label TLV */ void -dissect_ldp_label_mapping(tvbuff_t *tvb, guint offset, packet_info *pinfo, proto_tree *tree, guint length) +dissect_tlv_frame_label(tvbuff_t *tvb, guint offset, proto_tree *tree, int rem) { - guint rem = length, cc = 0; - - while (rem > 0) { - - rem -= (cc = dissect_tlv(tvb, offset, tree, rem)); - offset += cc; - - } - + proto_tree *ti = NULL, *val_tree = NULL; + guint8 len; + guint32 id; + + if(tree) { + if(rem != 4){ + proto_tree_add_text(tree, tvb, offset, rem,"Error processing TLV"); + return; + } + ti=proto_tree_add_text(tree, tvb, offset, rem, "Frame Relay Label"); + val_tree=proto_item_add_subtree(ti, ett_ldp_tlv_val); + if(val_tree == NULL) return; + + len=(guint8)(tvb_get_ntohs(tvb, offset)>>7) & 0x03; + proto_tree_add_uint_format(val_tree, hf_ldp_tlv_fr_label_len, tvb, offset, 2, len, "Number of DLCI bits: %s (%u)", val_to_str(len, tlv_fr_len_vals, "Unknown Length"), len); + + id=tvb_get_ntoh24(tvb, offset+1)&0x7FFFFF; + proto_tree_add_uint_format(val_tree, + hf_ldp_tlv_fr_label_dlci, tvb, offset+1, 3, id, "DLCI: %u", id); + } } -void -dissect_ldp_label_request(tvbuff_t *tvb, guint offset, packet_info *pinfo, proto_tree *tree, guint length) -{ - guint rem = length, cc = 0; - - while (rem > 0) { - - rem -= (cc = dissect_tlv(tvb, offset, tree, rem)); - offset += cc; - - } - -} +/* Dissect STATUS TLV */ void -dissect_ldp_label_withdrawal(tvbuff_t *tvb, guint offset, packet_info *pinfo, proto_tree *tree, guint length) +dissect_tlv_status(tvbuff_t *tvb, guint offset, proto_tree *tree, int rem) { - guint rem = length, cc = 0; + proto_tree *ti = NULL, *val_tree = NULL; + guint32 data; - while (rem > 0) { + if(tree) { + if(rem != 10){ + proto_tree_add_text(tree, tvb, offset, rem,"Error processing TLV"); + return; + } - rem -= (cc = dissect_tlv(tvb, offset, tree, rem)); - offset += cc; + ti=proto_tree_add_text(tree, tvb, offset, rem, "Status"); + val_tree=proto_item_add_subtree(ti, ett_ldp_tlv_val); + if(val_tree == NULL) return; - } + proto_tree_add_item(val_tree, hf_ldp_tlv_status_ebit, tvb, offset, 1, FALSE); + proto_tree_add_item(val_tree, hf_ldp_tlv_status_fbit, tvb, offset, 1, FALSE); + + data=tvb_get_ntohl(tvb, offset)&0x3FFFFFFF; + proto_tree_add_uint_format(val_tree, hf_ldp_tlv_status_data, tvb, offset, 4, data, "Status Data: %s (0x%X)", val_to_str(data, tlv_status_data, "Unknown Status Data"), data); + proto_tree_add_item(val_tree, hf_ldp_tlv_status_msg_id, tvb, offset+4, 4, FALSE); + proto_tree_add_item(val_tree, hf_ldp_tlv_status_msg_type, tvb, offset+8, 2, FALSE); + } } +/* Dissect Returned PDU TLV */ + void -dissect_ldp_label_release(tvbuff_t *tvb, guint offset, packet_info *pinfo, proto_tree *tree, guint length) +dissect_tlv_returned_pdu(tvbuff_t *tvb, guint offset, proto_tree *tree, int rem) { - guint rem = length, cc = 0; - - while (rem > 0) { - - rem -= (cc = dissect_tlv(tvb, offset, tree, rem)); - offset += cc; - - } - + proto_tree *ti = NULL, *val_tree = NULL; + + if(tree) { + if(rem < 10){ + proto_tree_add_text(tree, tvb, offset, rem,"Error processing TLV"); + return; + } + ti=proto_tree_add_text(tree, tvb, offset, rem, "Returned PDU"); + val_tree=proto_item_add_subtree(ti, ett_ldp_tlv_val); + if(val_tree == NULL) return; + + proto_tree_add_item(val_tree, hf_ldp_tlv_returned_version, tvb, offset, 2, FALSE); + proto_tree_add_item(val_tree, hf_ldp_tlv_returned_pdu_len, tvb, offset+2, 2, FALSE); + proto_tree_add_item(val_tree, hf_ldp_tlv_returned_lsr, tvb, offset+4, 4, FALSE); + proto_tree_add_item(val_tree, hf_ldp_tlv_returned_ls_id, tvb, offset+8, 2, FALSE); + offset += 10; + rem -= 10; + + if( rem > 0 ) { + /*XXX - dissect returned pdu data*/ + proto_tree_add_text(val_tree, tvb, offset, rem, "Returned PDU Data"); + } + } } +/* Dissect Returned MESSAGE TLV */ + void -dissect_ldp_label_abort_request(tvbuff_t *tvb, guint offset, packet_info *pinfo, proto_tree *tree, guint length) +dissect_tlv_returned_message(tvbuff_t *tvb, guint offset, proto_tree *tree, int rem) { - guint rem = length, cc = 0; + proto_tree *ti = NULL, *val_tree = NULL; + guint16 type; + + if(tree) { + if(rem < 4){ + proto_tree_add_text(tree, tvb, offset, rem,"Error processing TLV"); + return; + } + ti=proto_tree_add_text(tree, tvb, offset, rem, "Returned Message"); + val_tree=proto_item_add_subtree(ti, ett_ldp_tlv_val); + if(val_tree == NULL) return; + + proto_tree_add_item(val_tree, hf_ldp_tlv_returned_msg_ubit, tvb, offset, 1, FALSE); + + type=tvb_get_ntohs(tvb, offset)&0x7FFF; + proto_tree_add_uint_format(val_tree, hf_ldp_tlv_returned_msg_type, tvb, offset, 2, type, "Message Type: %s (0x%X)", val_to_str(type, ldp_message_types,"Unknown Message Type"), type); + + proto_tree_add_item(val_tree, hf_ldp_tlv_returned_msg_len, tvb, offset+2, 2, FALSE); + offset += 4; + rem -= 4; + + if( rem >= 4 ) { /*have msg_id*/ + proto_tree_add_item(val_tree, hf_ldp_tlv_returned_msg_id, tvb, offset, 4, FALSE); + offset += 4; + rem -= 4; + } + + if( rem > 0 ) { + /*XXX - dissect returned msg parameters*/ + proto_tree_add_text(val_tree, tvb, offset, rem, "Returned Message Parameters"); + } + } +} - while (rem > 0) { +/* Dissect the common hello params */ - rem -= (cc = dissect_tlv(tvb, offset, tree, rem)); - offset += cc; +void +dissect_tlv_common_hello_parms(tvbuff_t *tvb, guint offset, proto_tree *tree, int rem) +{ + proto_tree *ti = NULL, *val_tree = NULL; + + if (tree) { +#if 0 + ti = proto_tree_add_item(tree, hf_ldp_tlv_value, tvb, offset, rem, FALSE); + val_tree = proto_item_add_subtree(ti, ett_ldp_tlv_val); + if(val_tree == NULL) return; +#else + val_tree=tree; +#endif + proto_tree_add_item(val_tree, hf_ldp_tlv_val_hold, tvb, offset, 2, FALSE); + proto_tree_add_boolean(val_tree, hf_ldp_tlv_val_target, tvb, offset + 2, 2, FALSE); + proto_tree_add_boolean(val_tree, hf_ldp_tlv_val_request, tvb, offset + 2, 2, FALSE); + proto_tree_add_item(val_tree, hf_ldp_tlv_val_res, tvb, offset + 2, 2, FALSE); + } +} - } +/* Dissect the common session params */ +void +dissect_tlv_common_session_parms(tvbuff_t *tvb, guint offset, proto_tree *tree, int rem) +{ + proto_tree *ti = NULL, *val_tree = NULL; + + if (tree != NULL) { + ti = proto_tree_add_text(tree, tvb, offset, rem, "Parameters"); + if( rem != 14) { /*length of Comm Sess Parms tlv*/ + proto_tree_add_text(tree, tvb, offset, rem, "Error processing TLV"); + return ; + } + val_tree = proto_item_add_subtree(ti, ett_ldp_tlv_val); + + if(val_tree != NULL) { + /*Protocol Version*/ + proto_tree_add_item(val_tree, hf_ldp_tlv_sess_ver, tvb,offset, 2, FALSE); + + /*KeepAlive Time*/ + proto_tree_add_item(val_tree, hf_ldp_tlv_sess_ka, tvb,offset + 2, 2, FALSE); + + /*A bit*/ + proto_tree_add_item(val_tree, hf_ldp_tlv_sess_advbit,tvb, offset + 4, 1, FALSE); + + /*D bit*/ + proto_tree_add_item(val_tree, hf_ldp_tlv_sess_ldetbit,tvb, offset + 4, 1, FALSE); + + /*Path Vector Limit*/ + proto_tree_add_item(val_tree, hf_ldp_tlv_sess_pvlim,tvb, offset + 5, 1, FALSE); + + /*Max PDU Length*/ + proto_tree_add_item(val_tree, hf_ldp_tlv_sess_mxpdu,tvb, offset + 6, 2, FALSE); + + /*Rx LSR*/ + proto_tree_add_item(val_tree, hf_ldp_tlv_sess_rxlsr,tvb, offset + 8, 4, FALSE); + + /*Rx LS*/ + proto_tree_add_item(val_tree, hf_ldp_tlv_sess_rxls,tvb, offset + 12, 2, FALSE); + } + } } -static int -dissect_ldp_pdu(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) +/* Dissect the atm session params */ + +void +dissect_tlv_atm_session_parms(tvbuff_t *tvb, guint offset, proto_tree *tree, int rem) { - proto_tree *ldp_tree = NULL, *hdr_tree = NULL, *ldpid_tree = NULL; - proto_item *ldp_item = NULL, *hdr_item = NULL, *ldpid_item = NULL; - int msg_cnt = 0; - guint16 ldp_message = 0; - guint pdu_len; + proto_tree *ti = NULL, *val_tree = NULL, *lbl_tree = NULL; + guint8 numlr, ix; + guint16 id; + + if (tree != NULL) { + if(rem < 4) { + proto_tree_add_text(tree, tvb, offset, rem, + "Error processing TLV"); + return; + } + + ti = proto_tree_add_text(tree, tvb, offset, rem,"ATM Parameters"); + val_tree = proto_item_add_subtree(ti, ett_ldp_tlv_val); + + if(val_tree != NULL) { + proto_tree_add_item(val_tree, hf_ldp_tlv_sess_atm_merge,tvb, offset, 1, FALSE); + + /*get the number of label ranges*/ + numlr=(tvb_get_guint8(tvb, offset)>>2) & 0x0F; + proto_tree_add_uint_format(val_tree, hf_ldp_tlv_sess_atm_lr, + tvb, offset, 1, numlr, "Number of Label Range components: %u", + numlr); + + proto_tree_add_item(val_tree, hf_ldp_tlv_sess_atm_dir,tvb, offset, 1, FALSE); + + /*move into range components*/ + offset += 4; + rem -= 4; + ti = proto_tree_add_text(val_tree, tvb, offset, rem,"ATM Label Range Components"); + + if(numlr) { + val_tree=proto_item_add_subtree(ti,ett_ldp_tlv_val); + if( ! val_tree ) return; + } + /*now dissect ranges*/ + for(ix=1; numlr > 0 && rem >= 8; ix++, rem-=8, numlr--) { + ti=proto_tree_add_text(val_tree, tvb, offset, 8, + "ATM Label Range Component %u", ix); + lbl_tree=proto_item_add_subtree(ti, ett_ldp_tlv_val); + + if( lbl_tree == NULL ) break; + + id=tvb_get_ntohs(tvb, offset)&0x0FFF; + proto_tree_add_uint_format(lbl_tree, + hf_ldp_tlv_sess_atm_minvpi,tvb, offset, 2, id, "Minimum VPI: %u", id); + id=tvb_get_ntohs(tvb, offset+4)&0x0FFF; + proto_tree_add_uint_format(lbl_tree, + hf_ldp_tlv_sess_atm_maxvpi,tvb, (offset+4), 2, id, "Maximum VPI: %u", id); + + id=tvb_get_ntohs(tvb, offset+2); + proto_tree_add_uint_format(lbl_tree, + hf_ldp_tlv_sess_atm_minvci,tvb, offset+2, 2, id, "Minimum VCI: %u", id); + id=tvb_get_ntohs(tvb, offset+6); + proto_tree_add_uint_format(lbl_tree, + hf_ldp_tlv_sess_atm_maxvci,tvb, offset+6, 2, id, "Maximum VCI: %u", id); + + offset += 8; + } + if( rem || numlr) + proto_tree_add_text(val_tree, tvb, offset, rem,"Error processing TLV"); + } + } +} - if (check_col(pinfo->cinfo, COL_INFO)) - col_clear(pinfo->cinfo, COL_INFO); +/* Dissect the frame relay session params */ - if (tree) { /* Build the tree info ..., this is wrong! FIXME */ +void +dissect_tlv_frame_relay_session_parms(tvbuff_t *tvb, guint offset,proto_tree *tree, int rem) +{ + proto_tree *ti = NULL, *val_tree = NULL, *lbl_tree = NULL; + guint8 numlr, ix, len; + guint32 id; + + if (tree != NULL) { + if(rem < 4) { + proto_tree_add_text(tree, tvb, offset, rem, + "Error processing TLV"); + return; + } + + ti = proto_tree_add_text(tree, tvb, offset, rem, + "Frame Relay Parameters"); + val_tree = proto_item_add_subtree(ti, ett_ldp_tlv_val); + + if(val_tree != NULL) { + proto_tree_add_item(val_tree, hf_ldp_tlv_sess_fr_merge, + tvb, offset, 1, FALSE); + + /*get the number of label ranges*/ + numlr=(tvb_get_guint8(tvb, offset)>>2) & 0x0F; + proto_tree_add_uint_format(val_tree, hf_ldp_tlv_sess_fr_lr, + tvb, offset, 1, numlr, "Number of Label Range components: %u", + numlr); + + proto_tree_add_item(val_tree, hf_ldp_tlv_sess_fr_dir, + tvb, offset, 1, FALSE); + + /*move into range components*/ + offset += 4; + rem -= 4; + ti = proto_tree_add_text(val_tree, tvb, offset, rem, + "Frame Relay Label Range Components"); + + if(numlr) { + val_tree=proto_item_add_subtree(ti, + ett_ldp_tlv_val); + if( ! val_tree ) return; + } + + /*now dissect ranges*/ + for(ix=1; numlr > 0 && rem >= 8; ix++, rem-=8, numlr--) { + ti=proto_tree_add_text(val_tree, tvb, offset, 8, + "Frame Relay Label Range Component %u", ix); + lbl_tree=proto_item_add_subtree(ti, ett_ldp_tlv_val); + + if( lbl_tree == NULL ) break; + + len=(guint8)(tvb_get_ntohs(tvb, offset)>>7) & 0x03; + proto_tree_add_uint_format(lbl_tree, hf_ldp_tlv_sess_fr_len, tvb, offset, 2, len, "Number of DLCI bits: %s (%u)", val_to_str(len, tlv_fr_len_vals, "Unknown Length"), len); + + id=tvb_get_ntoh24(tvb, offset+1)&0x7FFFFF; + proto_tree_add_uint_format(lbl_tree, + hf_ldp_tlv_sess_fr_mindlci, tvb, offset+1, 3, id, "Minimum DLCI %u", id); + id=tvb_get_ntoh24(tvb, offset+5)&0x7FFFFF; + proto_tree_add_uint_format(lbl_tree, + hf_ldp_tlv_sess_fr_maxdlci, tvb, offset+5, 3, id, "Maximum DLCI %u", id); + + offset += 8; + } + + if( rem || numlr) + proto_tree_add_text(val_tree, tvb, offset, rem, + "Error processing TLV"); + } + } +} - ldp_item = proto_tree_add_item(tree, proto_ldp, tvb, offset, -1, FALSE); - ldp_tree = proto_item_add_subtree(ldp_item, ett_ldp); - } +/* Dissect a TLV and return the number of bytes consumed ... */ - /* Dissect LDP Header */ +int +dissect_tlv(tvbuff_t *tvb, guint offset, proto_tree *tree, int rem) +{ + guint16 type, typebak; + int length; + proto_tree *ti = NULL, *tlv_tree = NULL; - hdr_item = proto_tree_add_text(ldp_tree, tvb, offset, 10, "Header"); + length=tvb_reported_length_remaining(tvb, offset); + rem=MIN(rem, length); - hdr_tree = proto_item_add_subtree(hdr_item, ett_ldp_header); + if( rem < 4 ) {/*chk for minimum header*/ + if(tree) + proto_tree_add_text(tree, tvb, offset, rem,"Error processing TLV"); + return rem; + } + type = tvb_get_ntohs(tvb, offset) & 0x3FFF; + + length = tvb_get_ntohs(tvb, offset + 2), + rem -= 4; /*do not count header*/ + length = MIN(length, rem); /* Don't go haywire if a problem ... */ + + if (tree != NULL) { + /*chk for vendor-private*/ + if(type>=TLV_VENDOR_PRIVATE_START && type<=TLV_VENDOR_PRIVATE_END){ + typebak=type; /*keep type*/ + type=TLV_VENDOR_PRIVATE_START; + + /*chk for experimental*/ + } else if(type>=TLV_EXPERIMENTAL_START && type<=TLV_EXPERIMENTAL_END){ + typebak=type; /*keep type*/ + type=TLV_EXPERIMENTAL_START; + } + + ti = proto_tree_add_text(tree, tvb, offset, length + 4, "%s", + val_to_str(type, tlv_type_names, "Unknown TLV type (0x%04X)")); + tlv_tree = proto_item_add_subtree(ti, ett_ldp_tlv); + if(tlv_tree == NULL) return length+4; + + proto_tree_add_item(tlv_tree, hf_ldp_tlv_unknown, tvb, offset, 1, FALSE); + + proto_tree_add_uint_format(tlv_tree, hf_ldp_tlv_type, tvb, offset, 2, type, "TLV Type: %s (0x%X)", val_to_str(type, tlv_type_names, "Unknown TLV type"), type ); + + proto_tree_add_item(tlv_tree, hf_ldp_tlv_len, tvb, offset + 2, 2, FALSE); + + switch (type) { + + case TLV_FEC: + dissect_tlv_fec(tvb, offset + 4, tlv_tree, length); + break; + + case TLV_ADDRESS_LIST: + dissect_tlv_address_list(tvb, offset + 4, tlv_tree, length); + break; + + case TLV_HOP_COUNT: + if( length != 1 ) /*error, only one byte*/ + proto_tree_add_text(tlv_tree, tvb, offset + 4,length,"Error processing TLV"); + else + proto_tree_add_item(tlv_tree, hf_ldp_tlv_hc_value, tvb,offset + 4, length, FALSE); + break; + + case TLV_PATH_VECTOR: + dissect_tlv_path_vector(tvb, offset + 4, tlv_tree, length); + break; + + case TLV_GENERIC_LABEL: + if( length != 4 ) /*error, need only label*/ + proto_tree_add_text(tlv_tree, tvb, offset + 4, length,"Error processing TLV"); + else { + guint32 label=tvb_get_ntohl(tvb, offset+4) & 0x000FFFFF; + + proto_tree_add_uint_format(tlv_tree, hf_ldp_tlv_generic_label, + tvb, offset+4, length, label, "Generic Label: %u", label); + } + break; + + case TLV_ATM_LABEL: + dissect_tlv_atm_label(tvb, offset + 4, tlv_tree, length); + break; + + case TLV_FRAME_LABEL: + dissect_tlv_frame_label(tvb, offset + 4, tlv_tree, length); + break; + + case TLV_STATUS: + dissect_tlv_status(tvb, offset + 4, tlv_tree, length); + break; + + case TLV_EXTENDED_STATUS: + if( length != 4 ) /*error, need only status_code(guint32)*/ + proto_tree_add_text(tlv_tree, tvb, offset + 4, length,"Error processing TLV"); + else { + proto_tree_add_item(tlv_tree, hf_ldp_tlv_extstatus_data, tvb, offset + 4, length, FALSE); + } + break; + + case TLV_RETURNED_PDU: + dissect_tlv_returned_pdu(tvb, offset + 4, tlv_tree, length); + break; + + case TLV_RETURNED_MESSAGE: + dissect_tlv_returned_message(tvb, offset + 4, tlv_tree, length); + break; + + case TLV_COMMON_HELLO_PARMS: + dissect_tlv_common_hello_parms(tvb, offset + 4, tlv_tree, length); + break; + + case TLV_IPV4_TRANSPORT_ADDRESS: + if( length != 4 ) /*error, need only ipv4*/ + proto_tree_add_text(tlv_tree, tvb, offset + 4, length,"Error processing TLV"); + else { + proto_tree_add_item(tlv_tree, hf_ldp_tlv_ipv4_taddr, tvb, offset + 4, 4, FALSE); + } + break; + + case TLV_CONFIGURATION_SEQNO: + if( length != 4 ) /*error, need only seq_num(guint32)*/ + proto_tree_add_text(tlv_tree, tvb, offset + 4, length,"Error processing TLV"); + else { + proto_tree_add_item(tlv_tree, hf_ldp_tlv_config_seqno, tvb, offset + 4, 4, FALSE); + } + break; + + case TLV_IPV6_TRANSPORT_ADDRESS: + if( length != 16 ) /*error, need only ipv6*/ + proto_tree_add_text(tlv_tree, tvb, offset + 4, length,"Error processing TLV"); + else { + proto_tree_add_item(tlv_tree, hf_ldp_tlv_ipv6_taddr, tvb, offset + 4, 16, FALSE); + } + break; + + case TLV_COMMON_SESSION_PARMS: + dissect_tlv_common_session_parms(tvb, offset + 4, tlv_tree, length); + break; + + case TLV_ATM_SESSION_PARMS: + dissect_tlv_atm_session_parms(tvb, offset + 4, tlv_tree, length); + break; + + case TLV_FRAME_RELAY_SESSION_PARMS: + dissect_tlv_frame_relay_session_parms(tvb, offset + 4, tlv_tree, length); + break; + + case TLV_LABEL_REQUEST_MESSAGE_ID: + if( length != 4 ) /*error, need only one msgid*/ + proto_tree_add_text(tlv_tree, tvb, offset + 4, length,"Error processing TLV"); + else + proto_tree_add_item(tlv_tree, hf_ldp_tlv_lbl_req_msg_id, tvb,offset + 4,length, FALSE); + break; + + case TLV_VENDOR_PRIVATE_START: + if( length < 4 ) /*error, at least Vendor ID*/ + proto_tree_add_text(tlv_tree, tvb, offset + 4, length,"Error processing TLV"); + else { + proto_tree_add_item(tlv_tree, hf_ldp_tlv_vendor_id, tvb,offset + 4, 4, FALSE); + if( length > 4 ) /*have data*/ + proto_tree_add_text(tlv_tree, tvb, offset + 8, length-4,"Data"); + } + break; + + case TLV_EXPERIMENTAL_START: + if( length < 4 ) /*error, at least Experiment ID*/ + proto_tree_add_text(tlv_tree, tvb, offset + 4, length,"Error processing TLV"); + else { + proto_tree_add_item(tlv_tree, hf_ldp_tlv_experiment_id, tvb,offset + 4, 4, FALSE); + if( length > 4 ) /*have data*/ + proto_tree_add_text(tlv_tree, tvb, offset + 8, length-4,"Data"); + } + break; + + default: + proto_tree_add_item(tlv_tree, hf_ldp_tlv_value, tvb, offset + 4, length, FALSE); + break; + } + } - proto_tree_add_item(hdr_tree, hf_ldp_version, tvb, offset, 2, FALSE); + return length + 4; /* Length of the value field + header */ +} - offset += 2; - proto_tree_add_item(hdr_tree, hf_ldp_pdu_len, tvb, offset, 2, FALSE); - pdu_len = tvb_get_ntohs(tvb, offset); - proto_item_set_len(ldp_item, pdu_len + 2); +/* Dissect a Message and return the number of bytes consumed ... */ - /* - * XXX - do TCP reassembly, to handle LDP PDUs that cross TCP segment - * boundaries. - */ +int +dissect_msg(tvbuff_t *tvb, guint offset, packet_info *pinfo, proto_tree *tree, int rem) +{ + guint16 type, typebak; + guint8 extra=0; + int length, ao=0, co; + proto_tree *ti = NULL, *msg_tree = NULL; + + length=tvb_reported_length_remaining(tvb, offset); + rem=MIN(rem, length); + + if( rem < 8 ) {/*chk for minimum header = type + length + msg_id*/ + if( check_col(pinfo->cinfo, COL_INFO) ) + col_append_fstr(pinfo->cinfo, COL_INFO, "Bad Message"); + if(tree) + proto_tree_add_text(tree, tvb, offset, rem,"Error processing Message"); + return rem; + } + type = tvb_get_ntohs(tvb, offset) & 0x7FFF; + + /*chk for vendor-private*/ + if(type>=LDP_VENDOR_PRIVATE_START && type<=LDP_VENDOR_PRIVATE_END){ + typebak=type; /*keep type*/ + type=LDP_VENDOR_PRIVATE_START; + extra=4; + /*chk for experimental*/ + } else if(type>=LDP_EXPERIMENTAL_MESSAGE_START && type<=LDP_EXPERIMENTAL_MESSAGE_END){ + typebak=type; /*keep type*/ + type=LDP_EXPERIMENTAL_MESSAGE_START; + extra=4; + } - offset += 2; + if( (length = tvb_get_ntohs(tvb, offset + 2)) < (4+extra) ) {/*not enough data for type*/ + if( check_col(pinfo->cinfo, COL_INFO) ) + col_append_fstr(pinfo->cinfo, COL_INFO, "Bad Message Length "); + if(tree) + proto_tree_add_text(tree, tvb, offset, rem,"Error processing Message Length"); + return rem; + } + rem -= 4; + length = MIN(length, rem); /* Don't go haywire if a problem ... */ - if (pdu_len < 6) { - /* - * PDU is too short to hold the LDP identifier. - */ - proto_tree_add_text(hdr_tree, tvb, offset, pdu_len, - "PDU too short (%u bytes, should be at least 6) for LDP Identifier", - pdu_len); - offset += pdu_len; - return offset; - } + if( check_col(pinfo->cinfo, COL_INFO) ){ + col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", val_to_str(type, ldp_message_types, "Unknown Message (0x%04X)")); + } - ldpid_item = proto_tree_add_text(hdr_tree, tvb, offset, 6, "LDP Identifier"); + if( tree ){ + ti = proto_tree_add_text(tree, tvb, offset, length + 4, "%s", + val_to_str(type, ldp_message_types, "Unknown Message type (0x%04X)")); + msg_tree = proto_item_add_subtree(ti, ett_ldp_message); + if(msg_tree == NULL) return length+4; + + proto_tree_add_item(msg_tree, hf_ldp_msg_ubit, tvb, offset, 1, FALSE); + + type=tvb_get_ntohs(tvb, offset)&0x7FFF; + proto_tree_add_uint_format(msg_tree, hf_ldp_msg_type, tvb, offset, 2, type, "Message Type: %s (0x%X)", val_to_str(type, ldp_message_types,"Unknown Message Type"), type); + + proto_tree_add_item(msg_tree, hf_ldp_msg_len, tvb, offset+2, 2, FALSE); + proto_tree_add_item(msg_tree, hf_ldp_msg_id, tvb, offset+4, 4, FALSE); + if(extra){ + int hf_tmp=0; + + switch(type){ + case LDP_VENDOR_PRIVATE_START: + hf_tmp=hf_ldp_msg_vendor_id; + break; + case LDP_EXPERIMENTAL_MESSAGE_START: + hf_tmp=hf_ldp_msg_experiment_id; + break; + } + proto_tree_add_item(msg_tree, hf_tmp, tvb, offset+8, extra, FALSE); + } + } + + offset += (8+extra); + length -= (4+extra); + + if( tree ) + while( (length-ao) > 0 ) { + co=dissect_tlv(tvb, offset, msg_tree, length-ao); + offset += co; + ao += co; + } + + return length+8+extra; +} - ldpid_tree = proto_item_add_subtree(ldpid_item, ett_ldp_ldpid); +/* Dissect a PDU and return the number of bytes consumed ... */ - proto_tree_add_item(ldpid_tree, hf_ldp_lsr, tvb, offset, 4, FALSE); +int +dissect_ldp_pdu(tvbuff_t *tvb, guint offset, packet_info *pinfo, proto_tree *tree, int rem, guint ix) +{ + int length, ao=0, co; + proto_tree *ti=NULL, *pdu_tree = NULL; + + length=tvb_reported_length_remaining(tvb, offset); + rem=MIN(rem, length); + + if( rem < 10 ){/*don't even have a PDU header*/ +/*XXX Need changes in desegment_tcp to handle multiple requests*/ +#if 0 + if( pinfo->can_desegment && (pinfo->ptype==PT_TCP) && ldp_desegment ){ + pinfo->desegment_offset=offset; + pinfo->desegment_len=10-rem; + } +#else + if(tree) + proto_tree_add_text(tree, tvb, offset, rem,"Not enough bytes for PDU Hdr in TCP segment"); +#endif + return rem; + } - offset += 4; - pdu_len -= 4; + if( (length = tvb_get_ntohs(tvb, offset + 2)) < 6 ) {/*not enough*/ + if( check_col(pinfo->cinfo, COL_INFO) && ix ) + col_append_fstr(pinfo->cinfo, COL_INFO, "PDU %u: ", ix); + if( check_col(pinfo->cinfo, COL_INFO) ){ + col_append_fstr(pinfo->cinfo, COL_INFO, "Bad PDU Length "); + } + if(tree) + proto_tree_add_text(tree, tvb, offset, rem,"Error processing PDU Length"); + return rem; + } - proto_tree_add_item(ldpid_tree, hf_ldp_ls_id, tvb, offset, 2, FALSE); + rem -=4; + if( length>rem ){ + if( pinfo->can_desegment && (pinfo->ptype==PT_TCP) && ldp_desegment ){/*ask for more*/ + pinfo->desegment_offset=offset; + pinfo->desegment_len=length-rem; + }else { + if( check_col(pinfo->cinfo, COL_INFO) && ix ) + col_append_fstr(pinfo->cinfo, COL_INFO, "PDU %u: ", ix); + if( check_col(pinfo->cinfo, COL_INFO) ) + col_append_fstr(pinfo->cinfo, COL_INFO, "Bad PDU Length "); + if(tree) + proto_tree_add_text(tree, tvb, offset, rem+4,"Error processing PDU Length"); + } + return rem+4; + } + + if( check_col(pinfo->cinfo, COL_INFO) && ix ) + col_append_fstr(pinfo->cinfo, COL_INFO, "PDU %u: ", ix); - offset += 2; - pdu_len -= 2; + if( tree ){ + ti=proto_tree_add_protocol_format(tree, proto_ldp, tvb, offset, + length+4, "LDP PDU %u", ix); + pdu_tree = proto_item_add_subtree(ti, ett_ldp); + } - while (pdu_len > 0) { /* Dissect LDP TLV */ + if(pdu_tree){ + proto_tree_add_item(pdu_tree, hf_ldp_version, tvb, offset, 2, FALSE); + proto_tree_add_item(pdu_tree, hf_ldp_pdu_len, tvb, offset+2, 2, FALSE); + proto_tree_add_item(pdu_tree, hf_ldp_lsr, tvb, offset+4, 4, FALSE); + proto_tree_add_item(pdu_tree, hf_ldp_ls_id, tvb, offset+8, 2, FALSE); + } + offset += 10; + length -= 6; - guint msg_len; + while( (length-ao) > 0 ) { + co=dissect_msg(tvb, offset, pinfo, pdu_tree, length-ao); + offset += co; + ao += co; + } + + return length+10; +} - ldp_message = tvb_get_ntohs(tvb, offset) & 0x7FFF; /* Get the message type */ +static void +dissect_ldp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + if (check_col(pinfo->cinfo, COL_PROTOCOL)) + col_set_str(pinfo->cinfo, COL_PROTOCOL, "LDP"); - msg_len = tvb_get_ntohs(tvb, offset + 2); + if (check_col(pinfo->cinfo, COL_INFO)) + col_clear(pinfo->cinfo, COL_INFO); - if (check_col(pinfo->cinfo, COL_INFO)) { /* Check the type ... */ + dissect_ldp_pdu(tvb, 0, pinfo, tree, tvb_reported_length(tvb), 0); +} - if (msg_cnt > 0) - col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", - val_to_str(ldp_message, ldp_message_types, "Unknown Message (0x%04X)")); - else - col_add_fstr(pinfo->cinfo, COL_INFO, "%s", - val_to_str(ldp_message, ldp_message_types, "Unknown Message (0x%04X)")); - - } +static void +dissect_ldp_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + int offset=0, length, rtn; + guint ix=1; + + + if (check_col(pinfo->cinfo, COL_PROTOCOL)) + col_set_str(pinfo->cinfo, COL_PROTOCOL, "LDP"); + + if (check_col(pinfo->cinfo, COL_INFO)) + col_clear(pinfo->cinfo, COL_INFO); + + length=tvb_reported_length(tvb); + while (length > 0){ + rtn = dissect_ldp_pdu(tvb, offset, pinfo, tree, length, ix++); + offset += rtn; + length -= rtn; + } +} - msg_cnt++; +/* Register all the bits needed with the filtering engine */ - if (tree) { +void +proto_register_ldp(void) +{ + static hf_register_info hf[] = { + { &hf_ldp_req, + /* Change the following to the type you need */ + { "Request", "ldp.req", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }}, - proto_tree *ti = NULL, *msg_tree = NULL; + { &hf_ldp_rsp, + { "Response", "ldp.rsp", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }}, - /* FIXME: Account for vendor and experimental messages */ + { &hf_ldp_version, + { "Version", "ldp.hdr.version", FT_UINT16, BASE_DEC, NULL, 0x0, "LDP Version Number", HFILL }}, - ti = proto_tree_add_text(ldp_tree, tvb, offset, msg_len + 4, "%s", - val_to_str(ldp_message, ldp_message_types, "Unknown Message (0x%04X)")); + { &hf_ldp_pdu_len, + { "PDU Length", "ldp.hdr.pdu_len", FT_UINT16, BASE_DEC, NULL, 0x0, "LDP PDU Length", HFILL }}, - msg_tree = proto_item_add_subtree(ti, ett_ldp_message); - - proto_tree_add_item(msg_tree, hf_ldp_msg_type, tvb, offset, 2, FALSE); + { &hf_ldp_lsr, + { "LSR ID", "ldp.hdr.ldpid.lsr", FT_IPv4, BASE_HEX, NULL, 0x0, "LDP Label Space Router ID", HFILL }}, - proto_tree_add_item(msg_tree, hf_ldp_msg_len, tvb, offset + 2, 2, FALSE); + { &hf_ldp_ls_id, + { "Label Space ID", "ldp.hdr.ldpid.lsid", FT_UINT16, BASE_DEC, NULL, 0, "LDP Label Space ID", HFILL }}, - if (msg_len < 4) { - proto_tree_add_text(msg_tree, tvb, offset + 4, msg_len, - "Message too short (%u bytes, should be at least 4) for Message ID", - msg_len); - goto next; - } + { &hf_ldp_msg_ubit, + { "U bit", "ldp.msg.ubit", FT_BOOLEAN, 8, TFS(&ldp_message_ubit), 0x80, "Unknown Message Bit", HFILL }}, - proto_tree_add_item(msg_tree, hf_ldp_msg_id, tvb, offset + 4, 4, FALSE); + { &hf_ldp_msg_type, + { "Message Type", "ldp.msg.type", FT_UINT16, BASE_HEX, VALS(ldp_message_types), 0x7FFF, "LDP message type", HFILL }}, - if (msg_len == 4) { - /* Nothing past the message ID */ - goto next; - } + { &hf_ldp_msg_len, + { "Message Length", "ldp.msg.len", FT_UINT16, BASE_DEC, NULL, 0x0, "LDP Message Length (excluding message type and len)", HFILL }}, - switch (ldp_message) { + { &hf_ldp_msg_id, + { "Message ID", "ldp.msg.id", FT_UINT32, BASE_HEX, NULL, 0x0, "LDP Message ID", HFILL }}, - case LDP_NOTIFICATION: + { &hf_ldp_msg_vendor_id, + { "Vendor ID", "ldp.msg.vendor.id", FT_UINT32, BASE_HEX, NULL, 0x0, "LDP Vendor-private Message ID", HFILL }}, - dissect_ldp_notification(tvb, offset + 8, pinfo, msg_tree, msg_len - 4); + { &hf_ldp_msg_experiment_id, + { "Experiment ID", "ldp.msg.experiment.id", FT_UINT32, BASE_HEX, NULL, 0x0, "LDP Experimental Message ID", HFILL }}, - break; + { &hf_ldp_tlv_unknown, + { "TLV Unknown bits", "ldp.msg.tlv.unknown", FT_UINT8, BASE_HEX, VALS(tlv_unknown_vals), 0xC0, "TLV Unknown bits Field", HFILL }}, - case LDP_HELLO: + { &hf_ldp_tlv_type, + { "TLV Type", "ldp.msg.tlv.type", FT_UINT16, BASE_HEX, VALS(tlv_type_names), 0x3FFF, "TLV Type Field", HFILL }}, - dissect_ldp_hello(tvb, offset + 8, pinfo, msg_tree, msg_len - 4); + { &hf_ldp_tlv_len, + {"TLV Length", "ldp.msg.tlv.len", FT_UINT16, BASE_DEC, NULL, 0x0, "TLV Length Field", HFILL }}, - break; + { &hf_ldp_tlv_value, + { "TLV Value", "ldp.msg.tlv.value", FT_BYTES, BASE_NONE, NULL, 0x0, "TLV Value Bytes", HFILL }}, - case LDP_INITIALIZATION: + { &hf_ldp_tlv_val_hold, + { "Hold Time", "ldp.msg.tlv.hello.hold", FT_UINT16, BASE_DEC, NULL, 0x0, "Hello Common Parameters Hold Time", HFILL }}, - dissect_ldp_initialization(tvb, offset + 8, pinfo, msg_tree, msg_len - 4); + { &hf_ldp_tlv_val_target, + { "Targeted Hello", "ldp.msg.tlv.hello.targeted", FT_BOOLEAN, 8, TFS(&hello_targeted_vals), 0x80, "Hello Common Parameters Targeted Bit", HFILL }}, - break; + { &hf_ldp_tlv_val_request, + { "Hello Requested", "ldp,msg.tlv.hello.requested", FT_BOOLEAN, 8, TFS(&hello_requested_vals), 0x40, "Hello Common Parameters Hello Requested Bit", HFILL }}, + + { &hf_ldp_tlv_val_res, + { "Reserved", "ldp.msg.tlv.hello.res", FT_UINT16, BASE_HEX, NULL, 0x3FFF, "Hello Common Parameters Reserved Field", HFILL }}, - case LDP_KEEPALIVE: + { &hf_ldp_tlv_ipv4_taddr, + { "IPv4 Transport Address", "ldp.msg.tlv.ipv4.taddr", FT_IPv4, BASE_DEC, NULL, 0x0, "IPv4 Transport Address", HFILL }}, - dissect_ldp_keepalive(tvb, offset + 8, pinfo, msg_tree, msg_len - 4); - - break; + { &hf_ldp_tlv_config_seqno, + { "Configuration Sequence Number", "ldp.msg.tlv.hello.cnf_seqno", FT_UINT32, BASE_DEC, NULL, 0x0, "Hello Configuration Sequence Number", HFILL }}, - case LDP_ADDRESS: + { &hf_ldp_tlv_ipv6_taddr, + { "IPv6 Transport Address", "ldp.msg.tlv.ipv6.taddr", FT_IPv6, BASE_DEC, NULL, 0x0, "IPv6 Transport Address", HFILL }}, - dissect_ldp_address(tvb, offset + 8, pinfo, msg_tree, msg_len - 4); + { &hf_ldp_tlv_fec_wc, + { "FEC Element Type", "ldp.msg.tlv.fec.type", FT_UINT8, BASE_DEC, VALS(fec_types), 0x0, "Forwarding Equivalence Class Element Types", HFILL }}, - break; + { &hf_ldp_tlv_fec_af, + { "FEC Element Address Type", "ldp.msg.tlv.fec.af", FT_UINT16, BASE_DEC, VALS(afn_vals), 0x0, "Forwarding Equivalence Class Element Address Family", HFILL }}, - case LDP_ADDRESS_WITHDRAWAL: + { &hf_ldp_tlv_fec_len, + { "FEC Element Length", "ldp.msg.tlv.fec.len", FT_UINT8, BASE_DEC, NULL, 0x0, "Forwarding Equivalence Class Element Length", HFILL }}, - dissect_ldp_address_withdrawal(tvb, offset + 8, pinfo, msg_tree, msg_len - 4); + { &hf_ldp_tlv_fec_pfval, + { "FEC Element Prefix Value", "ldp.msg.tlv.fec.pfval", FT_STRING, BASE_NONE, NULL, 0x0, "Forwarding Equivalence Class Element Prefix", HFILL }}, - break; + { &hf_ldp_tlv_fec_hoval, + { "FEC Element Host Address Value", "ldp.msg.tlv.fec.hoval", FT_STRING, BASE_NONE, NULL, 0x0, "Forwarding Equivalence Class Element Address", HFILL }}, - case LDP_LABEL_MAPPING: + { &hf_ldp_tlv_addrl_addr_family, + { "Address Family", "ldp.msg.tlv.addrl.addr_family", FT_UINT16, BASE_DEC, VALS(afn_vals), 0x0, "Address Family List", HFILL }}, - dissect_ldp_label_mapping(tvb, offset + 8, pinfo, msg_tree, msg_len - 4); + { &hf_ldp_tlv_addrl_addr, + { "Address", "ldp.msg.tlv.addrl.addr", FT_STRING, BASE_NONE, NULL, 0x0, "Address", HFILL }}, - break; + { &hf_ldp_tlv_hc_value, + { "Hop Count Value", "ldp.msg.tlv.hc.value", FT_UINT8, BASE_DEC, NULL, 0x0, "Hop Count", HFILL }}, - case LDP_LABEL_REQUEST: + { &hf_ldp_tlv_pv_lsrid, + { "LSR Id", "ldp.msg.tlv.pv.lsrid", FT_IPv4, BASE_DEC, NULL, 0x0, "Path Vector LSR Id", HFILL }}, - dissect_ldp_label_request(tvb, offset + 8, pinfo, msg_tree, msg_len - 4); + { &hf_ldp_tlv_sess_ver, + { "Session Protocol Version", "ldp.msg.tlv.sess.ver", FT_UINT16, BASE_DEC, NULL, 0x0, "Common Session Parameters Protocol Version", HFILL }}, - break; + { &hf_ldp_tlv_sess_ka, + { "Session KeepAlive Time", "ldp.msg.tlv.sess.ka", FT_UINT16, BASE_DEC, NULL, 0x0, "Common Session Parameters KeepAlive Time", HFILL }}, - case LDP_LABEL_WITHDRAWAL: + { &hf_ldp_tlv_sess_advbit, + { "Session Label Advertisement Discipline", "ldp.msg.tlv.sess.advbit", + FT_BOOLEAN, 8, TFS(&tlv_sess_advbit_vals), 0x80, + "Common Session Parameters Label Advertisement Discipline", HFILL }}, - dissect_ldp_label_withdrawal(tvb, offset + 8, pinfo, msg_tree, msg_len - 4); + { &hf_ldp_tlv_sess_ldetbit, + { "Session Loop Detection", "ldp.msg.tlv.sess.ldetbit", FT_BOOLEAN, 8, TFS(&tlv_sess_ldetbit_vals), 0x40, "Common Session Parameters Loop Detection", HFILL }}, - break; + { &hf_ldp_tlv_sess_pvlim, + { "Session Path Vector Limit", "ldp.msg.tlv.sess.pvlim", FT_UINT8, BASE_DEC, NULL, 0x0, "Common Session Parameters Path Vector Limit", HFILL }}, - case LDP_LABEL_RELEASE: + { &hf_ldp_tlv_sess_mxpdu, + { "Session Max PDU Length", "ldp.msg.tlv.sess.mxpdu", FT_UINT16, BASE_DEC, NULL, 0x0, "Common Session Parameters Max PDU Length", HFILL }}, - dissect_ldp_label_release(tvb, offset + 8, pinfo, msg_tree, msg_len - 4); + { &hf_ldp_tlv_sess_rxlsr, + { "Session Receiver LSR Identifier", "ldp.msg.tlv.sess.rxlsr", FT_IPv4, BASE_DEC, NULL, 0x0, "Common Session Parameters LSR Identifier", HFILL }}, - break; + { &hf_ldp_tlv_sess_rxls, + { "Session Receiver Label Space Identifier", "ldp.msg.tlv.sess.rxlsr", FT_UINT16, BASE_DEC, NULL, 0x0, "Common Session Parameters Receiver Label Space Identifier", HFILL }}, - case LDP_LABEL_ABORT_REQUEST: + { &hf_ldp_tlv_sess_atm_merge, + { "Session ATM Merge Parameter", "ldp.msg.tlv.sess.atm.merge", FT_UINT8, BASE_DEC, VALS(tlv_atm_merge_vals), 0xC0, "Merge ATM Session Parameters", HFILL }}, - dissect_ldp_label_abort_request(tvb, offset + 8, pinfo, msg_tree, msg_len - 4); + { &hf_ldp_tlv_sess_atm_lr, + { "Number of ATM Label Ranges", "ldp.msg.tlv.sess.atm.lr", FT_UINT8, BASE_DEC, NULL, 0x3C, "Number of Label Ranges", HFILL }}, - break; + { &hf_ldp_tlv_sess_atm_dir, + { "Directionality", "ldp.msg.tlv.sess.atm.dir", FT_BOOLEAN, 8, TFS(&tlv_atm_dirbit), 0x02, "Lablel Directionality", HFILL }}, - default: + { &hf_ldp_tlv_sess_atm_minvpi, + { "Minimum VPI", "ldp.msg.tlv.sess.atm.minvpi", FT_UINT16, BASE_DEC, NULL, 0x0FFF, "Minimum VPI", HFILL }}, - /* Some sort of unknown message, treat as undissected data */ - proto_tree_add_text(msg_tree, tvb, offset + 8, msg_len - 4, - "Message data"); + { &hf_ldp_tlv_sess_atm_minvci, + { "Minimum VCI", "ldp.msg.tlv.sess.atm.minvci", FT_UINT16, BASE_DEC, NULL, 0x0, "Minimum VCI", HFILL }}, - break; + { &hf_ldp_tlv_sess_atm_maxvpi, + { "Maximum VPI", "ldp.msg.tlv.sess.atm.maxvpi", FT_UINT16, BASE_DEC, NULL, 0x0FFF, "Maximum VPI", HFILL }}, - } - - } + { &hf_ldp_tlv_sess_atm_maxvci, + { "Maximum VCI", "ldp.msg.tlv.sess.atm.maxvci", FT_UINT16, BASE_DEC, NULL, 0x0, "Maximum VCI", HFILL }}, -next: - offset += msg_len + 4; - pdu_len -= msg_len + 4; + { &hf_ldp_tlv_sess_fr_merge, + { "Session Frame Relay Merge Parameter", "ldp.msg.tlv.sess.fr.merge", FT_UINT8, BASE_DEC, VALS(tlv_fr_merge_vals), 0xC0, "Merge Frame Relay Session Parameters", HFILL }}, - } - return offset; -} + { &hf_ldp_tlv_sess_fr_lr, + { "Number of Frame Relay Label Ranges", "ldp.msg.tlv.sess.fr.lr", FT_UINT8, BASE_DEC, NULL, 0x3C, "Number of Label Ranges", HFILL }}, -static void -dissect_ldp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) -{ - if (check_col(pinfo->cinfo, COL_PROTOCOL)) - col_add_str(pinfo->cinfo, COL_PROTOCOL, "LDP"); + { &hf_ldp_tlv_sess_fr_dir, + { "Directionality", "ldp.msg.tlv.sess.fr.dir", FT_BOOLEAN, 8, TFS(&tlv_atm_dirbit), 0x02, "Lablel Directionality", HFILL }}, - dissect_ldp_pdu(tvb, 0, pinfo, tree); -} + { &hf_ldp_tlv_sess_fr_len, + { "Number of DLCI bits", "ldp.msg.tlv.sess.fr.len", FT_UINT16, BASE_DEC, VALS(tlv_fr_len_vals), 0x0180, "DLCI Number of bits", HFILL }}, -static void -dissect_ldp_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) -{ - int offset = 0; + { &hf_ldp_tlv_sess_fr_mindlci, + { "Minimum DLCI", "ldp.msg.tlv.sess.fr.mindlci", FT_UINT24, BASE_DEC, NULL, 0x7FFFFF, "Minimum DLCI", HFILL }}, - if (check_col(pinfo->cinfo, COL_PROTOCOL)) - col_add_str(pinfo->cinfo, COL_PROTOCOL, "LDP"); + { &hf_ldp_tlv_sess_fr_maxdlci, + { "Maximum DLCI", "ldp.msg.tlv.sess.fr.maxdlci", FT_UINT24, BASE_DEC, NULL, 0x7FFFFF, "Maximum DLCI", HFILL }}, - while (tvb_reported_length_remaining(tvb, offset) > 0) /* Dissect LDP PDUs */ - offset = dissect_ldp_pdu(tvb, offset, pinfo, tree); -} + { &hf_ldp_tlv_lbl_req_msg_id, + { "Label Request Message ID", "ldp.tlv.lbl_req_msg_id", FT_UINT32, BASE_HEX, NULL, 0x0, "Label Request Message to be aborted", HFILL }}, -/* Register all the bits needed with the filtering engine */ + { &hf_ldp_tlv_vendor_id, + { "Vendor ID", "ldp.msg.tlv.vendor_id", FT_UINT32, BASE_HEX, NULL, 0, "IEEE 802 Assigned Vendor ID", HFILL }}, -void -proto_register_ldp(void) -{ - static hf_register_info hf[] = { - { &hf_ldp_req, - /* Change the following to the type you need */ - { "Request", "ldp.req", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }}, + { &hf_ldp_tlv_experiment_id, + { "Experiment ID", "ldp.msg.tlv.experiment_id", FT_UINT32, BASE_HEX, NULL, 0, "Experiment ID", HFILL }}, - { &hf_ldp_rsp, - { "Response", "ldp.rsp", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }}, + { &hf_ldp_tlv_generic_label, + { "Generic Label", "ldp.msg.tlv.generic.label", FT_UINT32, BASE_HEX, NULL, 0x000FFFFF, "Generic Label", HFILL }}, - { &hf_ldp_version, - { "Version", "ldp.hdr.version", FT_UINT16, BASE_DEC, NULL, 0x0, "LDP Version Number", HFILL }}, + { &hf_ldp_tlv_atm_label_vbits, + { "V-bits", "ldp.msg.tlv.atm.label.vbits", FT_UINT8, BASE_HEX, VALS(tlv_atm_vbits_vals), 0x30, "ATM Label V Bits", HFILL }}, - { &hf_ldp_pdu_len, - { "PDU Length", "ldp.hdr.pdu_len", FT_UINT16, BASE_DEC, NULL, 0x0, "LDP PDU Length", HFILL }}, + { &hf_ldp_tlv_atm_label_vpi, + { "VPI", "ldp.msg.tlv.atm.label.vpi", FT_UINT16, BASE_DEC, NULL, 0x0FFF, "ATM Label VPI", HFILL }}, - { &hf_ldp_lsr, - { "LSR ID", "ldp.hdr.ldpid.lsr", FT_UINT32, BASE_HEX, NULL, 0x0, "LDP Label Space Router ID", HFILL }}, + { &hf_ldp_tlv_atm_label_vci, + { "VCI", "ldp.msg.tlv.atm.label.vci", FT_UINT16, BASE_DEC, NULL, 0, "ATM Label VCI", HFILL }}, - { &hf_ldp_ls_id, - { "Label Space ID", "ldp.hdr.ldpid.lsid", FT_UINT16, BASE_HEX, NULL, 0x0, "LDP Label Space ID", HFILL }}, + { &hf_ldp_tlv_fr_label_len, + { "Number of DLCI bits", "ldp.msg.tlv.fr.label.len", FT_UINT16, BASE_DEC, VALS(tlv_fr_len_vals), 0x0180, "DLCI Number of bits", HFILL }}, - { &hf_ldp_msg_type, - { "Message Type", "ldp.msg.type", FT_UINT16, BASE_HEX, VALS(ldp_message_types), 0x0, "LDP message type", HFILL }}, + { &hf_ldp_tlv_fr_label_dlci, + { "DLCI", "ldp.msg.tlv.fr.label.dlci", FT_UINT24, BASE_DEC, NULL, 0x7FFFFF, "FRAME RELAY Label DLCI", HFILL }}, - { &hf_ldp_msg_len, - { "Message Length", "ldp.msg.len", FT_UINT16, BASE_DEC, NULL, 0x0, "LDP Message Length (excluding message type and len)", HFILL }}, + { &hf_ldp_tlv_status_ebit, + { "E Bit", "ldp.msg.tlv.status.ebit", FT_BOOLEAN, 8, TFS(&tlv_status_ebit), 0x80, "Fatal Error Bit", HFILL }}, - { &hf_ldp_msg_id, - { "Message ID", "ldp.msg.id", FT_UINT32, BASE_HEX, NULL, 0x0, "LDP Message ID", HFILL }}, + { &hf_ldp_tlv_status_fbit, + { "F Bit", "ldp.msg.tlv.status.fbit", FT_BOOLEAN, 8, TFS(&tlv_status_fbit), 0x40, "Forward Bit", HFILL }}, - { &hf_ldp_tlv_type, - { "TLV Type", "ldp.msg.tlv.type", FT_UINT16, BASE_HEX, VALS(tlv_type_names), 0x0, "TLV Type Field", HFILL }}, + { &hf_ldp_tlv_status_data, + { "Status Data", "ldp.msg.tlv.status.data", FT_UINT32, BASE_HEX, VALS(tlv_status_data), 0x3FFFFFFF, "Status Data", HFILL }}, - { &hf_ldp_tlv_len, - {"TLV Length", "ldp.msg.tlv.len", FT_UINT16, BASE_DEC, NULL, 0x0, "TLV Length Field", HFILL }}, + { &hf_ldp_tlv_status_msg_id, + { "Message ID", "ldp.msg.tlv.status.msg.id", FT_UINT32, BASE_HEX, NULL, 0x0, "Identifies peer message to which Status TLV refers", HFILL }}, - { &hf_ldp_tlv_value, - { "TLV Value", "ldp.msg.tlv.value", FT_BYTES, BASE_NONE, NULL, 0x0, "TLV Value Bytes", HFILL }}, + { &hf_ldp_tlv_status_msg_type, + { "Message Type", "ldp.msg.tlv.status.msg.type", FT_UINT16, BASE_HEX, VALS(ldp_message_types), 0x0, "Type of peer message to which Status TLV refers", HFILL }}, - { &hf_ldp_tlv_val_hold, - { "Hold Time", "ldp.msg.tlv.hello.hold", FT_UINT16, BASE_DEC, NULL, 0x0, "Hello Common Parameters Hold Time", HFILL }}, + { &hf_ldp_tlv_extstatus_data, + { "Extended Status Data", "ldp.msg.tlv.extstatus.data", FT_UINT32, BASE_HEX, NULL, 0x0, "Extended Status Data", HFILL }}, - { &hf_ldp_tlv_val_target, - { "Targeted Hello", "ldp.msg.tlv.hello.targeted", FT_BOOLEAN, 8, TFS(&hello_targeted_vals), 0x80, "Hello Common Parameters Targeted Bit", HFILL }}, + { &hf_ldp_tlv_returned_version, + { "Returned PDU Version", "ldp.msg.tlv.returned.version", FT_UINT16, BASE_DEC, NULL, 0x0, "LDP Version Number", HFILL }}, - { &hf_ldp_tlv_val_request, - { "Hello Requested", "ldp,msg.tlv.hello.requested", FT_BOOLEAN, 8, TFS(&hello_requested_vals), 0x40, "Hello Common Parameters Hello Requested Bit", HFILL }}, - - { &hf_ldp_tlv_val_res, - { "Reserved", "ldp.msg.tlv.hello.res", FT_UINT16, BASE_HEX, NULL, 0x3FFF, "Hello Common Parameters Reserved Field", HFILL }}, + { &hf_ldp_tlv_returned_pdu_len, + { "Returned PDU Length", "ldp.msg.tlv.returned.pdu_len", FT_UINT16, BASE_DEC, NULL, 0x0, "LDP PDU Length", HFILL }}, - { &hf_ldp_tlv_config_seqno, - { "Configuration Sequence Number", "ldp.msg.tlv.hello.cnf_seqno", FT_UINT32, BASE_HEX, NULL, 0x0, "Hello COnfiguration Sequence Number", HFILL }}, + { &hf_ldp_tlv_returned_lsr, + { "Returned PDU LSR ID", "ldp.msg.tlv.returned.ldpid.lsr", FT_IPv4, BASE_DEC, NULL, 0x0, "LDP Label Space Router ID", HFILL }}, - { &hf_ldp_tlv_fec_wc, - { "FEC Element Type", "ldp.msg.tlv.fec.type", FT_UINT8, BASE_DEC, VALS(fec_types), 0x0, "Forwarding Equivalence Class Element Types", HFILL }}, + { &hf_ldp_tlv_returned_ls_id, + { "Returned PDU Label Space ID", "ldp.msg.tlv.returned.ldpid.lsid", FT_UINT16, BASE_HEX, NULL, 0x0, "LDP Label Space ID", HFILL }}, - { &hf_ldp_tlv_fec_af, - { "FEC Element Address Type", "ldp.msg.tlv.fec.af", FT_UINT16, BASE_DEC, VALS(afn_vals), 0x0, "Forwarding Equivalence Class Element Address Family", HFILL }}, + { &hf_ldp_tlv_returned_msg_ubit, + { "Returned Message Unknown bit", "ldp.msg.tlv.returned.msg.ubit", FT_UINT8, BASE_HEX, TFS(&ldp_message_ubit), 0x80, "Message Unknown bit", HFILL }}, - { &hf_ldp_tlv_fec_len, - { "FEC Element Length", "ldp.msg.tlv.fec.len", FT_UINT8, BASE_DEC, NULL, 0x0, "Forwarding Equivalence Class Element Length", HFILL }}, + { &hf_ldp_tlv_returned_msg_type, + { "Returned Message Type", "ldp.msg.tlv.returned.msg.type", FT_UINT16, BASE_HEX, VALS(ldp_message_types), 0x7FFF, "LDP message type", HFILL }}, - { &hf_ldp_tlv_fec_pfval, - { "FEC Element Prefix Value", "ldp.msg.tlv.fec.pfval", FT_IPv4, BASE_DEC, NULL, 0x0, "Forwarding Equivalence Class Element Prefix", HFILL }}, + { &hf_ldp_tlv_returned_msg_len, + { "Returned Message Length", "ldp.msg.tlv.returned.msg.len", FT_UINT16, BASE_DEC, NULL, 0x0, "LDP Message Length (excluding message type and len)", HFILL }}, - { &hf_ldp_tlv_generic_label, - { "Generic Label", "ldp.msg.tlv.label", FT_UINT32, BASE_HEX, NULL, 0x0, "Label Mapping Generic Label", HFILL }}, + { &hf_ldp_tlv_returned_msg_id, + { "Returned Message ID", "ldp.msg.tlv.returned.msg.id", FT_UINT32, BASE_HEX, NULL, 0x0, "LDP Message ID", HFILL }} }; + static gint *ett[] = { &ett_ldp, &ett_ldp_header, @@ -876,6 +1673,10 @@ proto_register_ldp(void) " than the default of 646)", 10, &global_ldp_udp_port); + prefs_register_bool_preference(ldp_module, "desegment_ldp_messages", + "Desegment all LDP messages spanning multiple TCP segments", + "Whether the LDP dissector should desegment all messages spanning multiple TCP segments", + &ldp_desegment); } /* The registration hand-off routine */ |