wireshark/packet-ldp.c

1887 lines
64 KiB
C

/* packet-ldp.c
* Routines for LDP (RFC 3036) packet disassembly
*
* $Id: packet-ldp.c,v 1.30 2002/03/16 23:15:45 guy Exp $
*
* Copyright (c) November 2000 by Richard Sharpe <rsharpe@ns.aus.com>
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
* Copyright 1999 Gerald Combs
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <time.h>
#include <glib.h>
#include <string.h>
#include <epan/packet.h>
#include <epan/resolv.h>
#include "prefs.h"
#include "afn.h"
#define TCP_PORT_LDP 646
#define UDP_PORT_LDP 646
void proto_reg_handoff_ldp(void);
static int proto_ldp = -1;
/* Delete the following if you do not use it, or add to it if you need */
static int hf_ldp_req = -1;
static int hf_ldp_rsp = -1;
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 hf_ldp_tlv_fec_vc_controlword = -1;
static int hf_ldp_tlv_fec_vc_vctype = -1;
static int hf_ldp_tlv_fec_vc_infolength = -1;
static int hf_ldp_tlv_fec_vc_groupid = -1;
static int hf_ldp_tlv_fec_vc_vcid = -1;
static int hf_ldp_tlv_fec_vc_intparam_length = -1;
static int hf_ldp_tlv_fec_vc_intparam_mtu = -1;
static int hf_ldp_tlv_fec_vc_intparam_id = -1;
static int hf_ldp_tlv_fec_vc_intparam_maxcatmcells = -1;
static int hf_ldp_tlv_fec_vc_intparam_desc = -1;
static int hf_ldp_tlv_fec_vc_intparam_cembytes = -1;
static int ett_ldp = -1;
static int ett_ldp_header = -1;
static int ett_ldp_ldpid = -1;
static int ett_ldp_message = -1;
static int ett_ldp_tlv = -1;
static int ett_ldp_tlv_val = -1;
static int ett_ldp_fec = -1;
static int ett_ldp_fec_vc_interfaceparam = -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;
static int global_ldp_udp_port = UDP_PORT_LDP;
/*
* The following define all the TLV types I know about
*/
#define TLV_FEC 0x0100
#define TLV_ADDRESS_LIST 0x0101
#define TLV_HOP_COUNT 0x0103
#define TLV_PATH_VECTOR 0x0104
#define TLV_GENERIC_LABEL 0x0200
#define TLV_ATM_LABEL 0x0201
#define TLV_FRAME_LABEL 0x0202
#define TLV_STATUS 0x0300
#define TLV_EXTENDED_STATUS 0x0301
#define TLV_RETURNED_PDU 0x0302
#define TLV_RETURNED_MESSAGE 0x0303
#define TLV_COMMON_HELLO_PARMS 0x0400
#define TLV_IPV4_TRANSPORT_ADDRESS 0x0401
#define TLV_CONFIGURATION_SEQNO 0x0402
#define TLV_IPV6_TRANSPORT_ADDRESS 0x0403
#define TLV_COMMON_SESSION_PARMS 0x0500
#define TLV_ATM_SESSION_PARMS 0x0501
#define TLV_FRAME_RELAY_SESSION_PARMS 0x0502
#define TLV_LABEL_REQUEST_MESSAGE_ID 0x0600
#define TLV_VENDOR_PRIVATE_START 0x3E00
#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" },
{ 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}
};
/*
* The following define all the message types I know about
*/
#define LDP_NOTIFICATION 0x0001
#define LDP_HELLO 0x0100
#define LDP_INITIALIZATION 0x0200
#define LDP_KEEPALIVE 0x0201
#define LDP_ADDRESS 0x0300
#define LDP_ADDRESS_WITHDRAWAL 0x0301
#define LDP_LABEL_MAPPING 0x0400
#define LDP_LABEL_REQUEST 0x0401
#define LDP_LABEL_WITHDRAWAL 0x0402
#define LDP_LABEL_RELEASE 0x0403
#define LDP_LABEL_ABORT_REQUEST 0x0404
#define LDP_VENDOR_PRIVATE_START 0x3E00
#define LDP_VENDOR_PRIVATE_END 0x3EFF
#define LDP_EXPERIMENTAL_MESSAGE_START 0x3F00
#define LDP_EXPERIMENTAL_MESSAGE_END 0x3FFF
static const value_string ldp_message_types[] = {
{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 tlv_unknown_vals[] = {
{0, "Known TLV"},
{1, "Known TLV"},
{2, "Unknown TLV, do not Forward"},
{3, "Unknown TLV, do Forward"},
{0, NULL}
};
#define WILDCARD_FEC 1
#define PREFIX_FEC 2
#define HOST_FEC 3
#define VC_FEC 0x80 /* draft-martini-l2circuit-trans-mpls */
static const value_string fec_types[] = {
{WILDCARD_FEC, "Wildcard FEC"},
{PREFIX_FEC, "Prefix FEC"},
{HOST_FEC, "Host Address FEC"},
{VC_FEC, "Virtual Circuit FEC"},
{0, NULL}
};
static const value_string fec_vc_types_vals[] = {
{0x0001, "Frame Relay DLCI"},
{0x0002, "ATM VCC transport"},
{0x0003, "ATM VPC transport"},
{0x0004, "Ethernet VLAN"},
{0x0005, "Ethernet"},
{0x0006, "HDLC"},
{0x0007, "PPP"},
{0x0009, "ATM VCC cell transport"},
{0x8008, "CEM"},
{0x000A, "ATM VPC cell transport"},
{0, NULL}
};
#define FEC_VC_INTERFACEPARAM_MTU 0x01
#define FEC_VC_INTERFACEPARAM_MAXCATMCELLS 0x02
#define FEC_VC_INTERFACEPARAM_DESCRIPTION 0x03
#define FEC_VC_INTERFACEPARAM_CEMBYTES 0x04
#define FEC_VC_INTERFACEPARAM_CEMOPTIONS 0x05
static const value_string fec_vc_interfaceparm[] = {
{FEC_VC_INTERFACEPARAM_MTU, "MTU"},
{FEC_VC_INTERFACEPARAM_MAXCATMCELLS, "Max Concatenated ATM cells"},
{FEC_VC_INTERFACEPARAM_DESCRIPTION, "Interface Description"},
{FEC_VC_INTERFACEPARAM_CEMBYTES, "CEM Payload Bytes"},
{FEC_VC_INTERFACEPARAM_CEMOPTIONS, "CEM options"}
};
static const true_false_string fec_vc_cbit = {
"Contorl Word Present",
"Control Word NOT Present"
};
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}
};
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}
};
static const value_string tlv_fr_merge_vals[] = {
{0, "Merge not supported"},
{1, "Merge supported"},
{2, "Unspecified"},
{3, "Unspecified"},
{0, NULL}
};
static const value_string tlv_fr_len_vals[] = {
{0, "10 bits"},
{1, "Reserved"},
{2, "23 bits"},
{3, "Reserved"},
{0, NULL}
};
static const true_false_string tlv_atm_dirbit = {
"Bidirectional capability",
"Unidirectional capability"
};
static const true_false_string hello_requested_vals = {
"Source requests periodic hellos",
"Source does not request periodic hellos"
};
static const true_false_string tlv_sess_advbit_vals = {
"Downstream On Demand proposed",
"Downstream Unsolicited proposed"
};
static const true_false_string tlv_sess_ldetbit_vals = {
"Loop Detection Enabled",
"Loop Detection Disabled"
};
static const true_false_string tlv_status_ebit = {
"Fatal Error Notification",
"Advisory Notification"
};
static const true_false_string tlv_status_fbit = {
"Notification should be Forwarded",
"Notification should NOT be Forwarded"
};
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"},
{0x01000001,"Unexpected Diff-Serv TLV"},
{0x01000002,"Unsupported PHB"},
{0x01000003,"Invalid EXP<->PHB Mapping"},
{0x01000004,"Unsupported PSC"},
{0x01000005,"Per-LSP context allocation failure"},
{0x04000001,"Bad Explicit Routing TLV Error"},
{0x04000002,"Bad Strict Node Error"},
{0x04000003,"Bad Strict Node Error"},
{0x04000004,"Bad Initial ER-Hop Error"},
{0x04000005,"Resource Unavailable"},
{0x04000006,"Traffic Parameters Unavailable"},
{0x04000007,"LSP Preempted"},
{0x04000008,"Modify Request Not Supported"},
{0x20000001,"Illegal C-Bit"},
{0x20000002,"Wrong C-Bit"},
{0, NULL}
};
/* 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, *vcintparam_tree=NULL;
guint16 family, ix=1, ax;
guint8 addr_size=0, *addr, implemented, prefix_len_octets, prefix_len, host_len, vc_len;
guint8 intparam_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;
case VC_FEC:
if( rem < 8 ){/*not enough bytes for a minimal VC_FEC*/
proto_tree_add_text(val_tree, tvb, offset, rem, "Error in FEC Element %u", ix);
return;
}
vc_len = tvb_get_guint8 (tvb, offset+3);
ti = proto_tree_add_text(val_tree, tvb, offset, 8+vc_len, "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);
proto_tree_add_item(fec_tree, hf_ldp_tlv_fec_vc_controlword, tvb, offset+1, 1, FALSE);
proto_tree_add_item(fec_tree, hf_ldp_tlv_fec_vc_vctype, tvb, offset+1, 2, FALSE);
proto_tree_add_item(fec_tree, hf_ldp_tlv_fec_vc_infolength, tvb, offset+3,1,FALSE);
proto_tree_add_item(fec_tree, hf_ldp_tlv_fec_vc_groupid,tvb, offset +4, 4, FALSE);
rem -=8;
offset +=8;
if ( (vc_len > 3) && ( rem > 3 ) ) { /* there is enough room for vcid */
proto_tree_add_item(fec_tree, hf_ldp_tlv_fec_vc_vcid,tvb, offset, 4, FALSE);
proto_item_append_text (ti," VCID: %u",tvb_get_ntohl(tvb,offset));
} else {
proto_tree_add_text(val_tree,tvb,offset +4, 8 +vc_len, "VC FEC size format error");
return;
}
rem -= 4;
vc_len -= 4;
offset += 4;
while ( (vc_len > 1) && (rem > 1) ) { /* enough to include id and length */
intparam_len = tvb_get_guint8(tvb, offset+1);
ti = proto_tree_add_text(fec_tree, tvb, offset, 4, "Interface Paramameter");
vcintparam_tree = proto_item_add_subtree(ti, ett_ldp_fec_vc_interfaceparam);
if(vcintparam_tree == NULL) return;
proto_tree_add_item(vcintparam_tree,hf_ldp_tlv_fec_vc_intparam_id,tvb,offset,1,FALSE);
proto_tree_add_item(vcintparam_tree,hf_ldp_tlv_fec_vc_intparam_length,tvb, offset+1, 1, FALSE);
if ( (vc_len -intparam_len) <0 && (rem -intparam_len) <0 ) { /* error condition */
proto_tree_add_text(vcintparam_tree, tvb, offset +2, MIN(vc_len,rem), "malformed data");
return;
}
switch (tvb_get_guint8(tvb, offset)) {
case FEC_VC_INTERFACEPARAM_MTU:
proto_item_append_text(ti,": MTU %u", tvb_get_ntohs(tvb,offset+2));
proto_tree_add_item(vcintparam_tree,hf_ldp_tlv_fec_vc_intparam_mtu,tvb, offset+2, 2, FALSE);
break;
case FEC_VC_INTERFACEPARAM_MAXCATMCELLS:
proto_item_append_text(ti,": Max ATM Concat Cells %u", tvb_get_ntohs(tvb,offset+2));
proto_tree_add_item(vcintparam_tree,hf_ldp_tlv_fec_vc_intparam_maxcatmcells,tvb, offset+2, 2, FALSE);
break;
case FEC_VC_INTERFACEPARAM_DESCRIPTION:
proto_item_append_text(ti,": Description");
proto_tree_add_item(vcintparam_tree,hf_ldp_tlv_fec_vc_intparam_desc,tvb, offset+2, (intparam_len -2), FALSE);
break;
case FEC_VC_INTERFACEPARAM_CEMBYTES:
proto_item_append_text(ti,": CEM Payload Bytes %u", tvb_get_ntohs(tvb,offset+2));
proto_tree_add_item(vcintparam_tree,hf_ldp_tlv_fec_vc_intparam_cembytes,tvb, offset+2, 2, FALSE);
break;
case FEC_VC_INTERFACEPARAM_CEMOPTIONS:
/* draft-malis-sonet-ces-mpls CEM options still undefined */
default: /* unknown */
proto_item_append_text(ti," unknown");
proto_tree_add_text(vcintparam_tree,tvb, offset+2, (intparam_len -2), "Unknown data");
return;
}
rem -= intparam_len;
vc_len -= intparam_len;
offset += intparam_len;
}
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++;
}
}
}
/* Dissect Address List TLV */
void
dissect_tlv_address_list(tvbuff_t *tvb, guint offset, proto_tree *tree, int rem)
{
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 Path Vector TLV */
void
dissect_tlv_path_vector(tvbuff_t *tvb, guint offset, proto_tree *tree, int rem)
{
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");
}
}
/* Dissect ATM Label TLV */
void
dissect_tlv_atm_label(tvbuff_t *tvb, guint offset, proto_tree *tree, int rem)
{
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);
}
}
/* Dissect FRAME RELAY Label TLV */
void
dissect_tlv_frame_label(tvbuff_t *tvb, guint offset, proto_tree *tree, int rem)
{
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);
}
}
/* Dissect STATUS TLV */
void
dissect_tlv_status(tvbuff_t *tvb, guint offset, proto_tree *tree, int rem)
{
proto_tree *ti = NULL, *val_tree = NULL;
guint32 data;
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, "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_tlv_returned_pdu(tvbuff_t *tvb, guint offset, proto_tree *tree, int rem)
{
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_tlv_returned_message(tvbuff_t *tvb, guint offset, proto_tree *tree, int rem)
{
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");
}
}
}
/* 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) {
#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_item(val_tree, hf_ldp_tlv_val_target, tvb, offset + 2, 1, FALSE);
proto_tree_add_item(val_tree, hf_ldp_tlv_val_request, tvb, offset + 2, 1, 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);
}
}
}
/* Dissect the atm session params */
void
dissect_tlv_atm_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;
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");
}
}
}
/* Dissect the frame relay session params */
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");
}
}
}
/* Dissect a TLV and return the number of bytes consumed ... */
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;
length=tvb_reported_length_remaining(tvb, offset);
rem=MIN(rem, length);
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;
}
}
return length + 4; /* Length of the value field + header */
}
/* Dissect a Message and return the number of bytes consumed ... */
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;
}
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( 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)"));
}
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;
}
/* Dissect a PDU and return the number of bytes consumed ... */
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;
}
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;
}
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);
if( tree ){
ti=proto_tree_add_protocol_format(tree, proto_ldp, tvb, offset,
length+4, ix?"LDP PDU %u":"LDP PDU", ix);
pdu_tree = proto_item_add_subtree(ti, ett_ldp);
}
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;
while( (length-ao) > 0 ) {
co=dissect_msg(tvb, offset, pinfo, pdu_tree, length-ao);
offset += co;
ao += co;
}
return length+10;
}
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");
if (check_col(pinfo->cinfo, COL_INFO))
col_clear(pinfo->cinfo, COL_INFO);
dissect_ldp_pdu(tvb, 0, pinfo, tree, tvb_reported_length(tvb), 0);
}
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;
}
}
/* Register all the bits needed with the filtering engine */
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_rsp,
{ "Response", "ldp.rsp", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
{ &hf_ldp_version,
{ "Version", "ldp.hdr.version", FT_UINT16, BASE_DEC, NULL, 0x0, "LDP Version Number", HFILL }},
{ &hf_ldp_pdu_len,
{ "PDU Length", "ldp.hdr.pdu_len", FT_UINT16, BASE_DEC, NULL, 0x0, "LDP PDU Length", HFILL }},
{ &hf_ldp_lsr,
{ "LSR ID", "ldp.hdr.ldpid.lsr", FT_IPv4, BASE_HEX, NULL, 0x0, "LDP Label Space Router ID", HFILL }},
{ &hf_ldp_ls_id,
{ "Label Space ID", "ldp.hdr.ldpid.lsid", FT_UINT16, BASE_DEC, NULL, 0, "LDP Label Space ID", HFILL }},
{ &hf_ldp_msg_ubit,
{ "U bit", "ldp.msg.ubit", FT_BOOLEAN, 8, TFS(&ldp_message_ubit), 0x80, "Unknown Message Bit", HFILL }},
{ &hf_ldp_msg_type,
{ "Message Type", "ldp.msg.type", FT_UINT16, BASE_HEX, VALS(ldp_message_types), 0x7FFF, "LDP message type", 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_msg_id,
{ "Message ID", "ldp.msg.id", FT_UINT32, BASE_HEX, NULL, 0x0, "LDP Message ID", HFILL }},
{ &hf_ldp_msg_vendor_id,
{ "Vendor ID", "ldp.msg.vendor.id", FT_UINT32, BASE_HEX, NULL, 0x0, "LDP Vendor-private Message ID", HFILL }},
{ &hf_ldp_msg_experiment_id,
{ "Experiment ID", "ldp.msg.experiment.id", FT_UINT32, BASE_HEX, NULL, 0x0, "LDP Experimental Message ID", HFILL }},
{ &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 }},
{ &hf_ldp_tlv_type,
{ "TLV Type", "ldp.msg.tlv.type", FT_UINT16, BASE_HEX, VALS(tlv_type_names), 0x3FFF, "TLV Type Field", HFILL }},
{ &hf_ldp_tlv_len,
{"TLV Length", "ldp.msg.tlv.len", FT_UINT16, BASE_DEC, NULL, 0x0, "TLV Length Field", HFILL }},
{ &hf_ldp_tlv_value,
{ "TLV Value", "ldp.msg.tlv.value", FT_BYTES, BASE_NONE, NULL, 0x0, "TLV Value Bytes", 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_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_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_ipv4_taddr,
{ "IPv4 Transport Address", "ldp.msg.tlv.ipv4.taddr", FT_IPv4, BASE_DEC, NULL, 0x0, "IPv4 Transport Address", HFILL }},
{ &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 }},
{ &hf_ldp_tlv_ipv6_taddr,
{ "IPv6 Transport Address", "ldp.msg.tlv.ipv6.taddr", FT_IPv6, BASE_DEC, NULL, 0x0, "IPv6 Transport Address", 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_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_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_fec_pfval,
{ "FEC Element Prefix Value", "ldp.msg.tlv.fec.pfval", FT_STRING, BASE_NONE, NULL, 0x0, "Forwarding Equivalence Class Element Prefix", HFILL }},
{ &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 }},
{ &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 }},
{ &hf_ldp_tlv_addrl_addr,
{ "Address", "ldp.msg.tlv.addrl.addr", FT_STRING, BASE_NONE, NULL, 0x0, "Address", HFILL }},
{ &hf_ldp_tlv_hc_value,
{ "Hop Count Value", "ldp.msg.tlv.hc.value", FT_UINT8, BASE_DEC, NULL, 0x0, "Hop Count", HFILL }},
{ &hf_ldp_tlv_pv_lsrid,
{ "LSR Id", "ldp.msg.tlv.pv.lsrid", FT_IPv4, BASE_DEC, NULL, 0x0, "Path Vector LSR Id", HFILL }},
{ &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 }},
{ &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 }},
{ &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 }},
{ &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 }},
{ &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 }},
{ &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 }},
{ &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 }},
{ &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 }},
{ &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 }},
{ &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 }},
{ &hf_ldp_tlv_sess_atm_dir,
{ "Directionality", "ldp.msg.tlv.sess.atm.dir", FT_BOOLEAN, 8, TFS(&tlv_atm_dirbit), 0x02, "Lablel Directionality", HFILL }},
{ &hf_ldp_tlv_sess_atm_minvpi,
{ "Minimum VPI", "ldp.msg.tlv.sess.atm.minvpi", FT_UINT16, BASE_DEC, NULL, 0x0FFF, "Minimum VPI", HFILL }},
{ &hf_ldp_tlv_sess_atm_minvci,
{ "Minimum VCI", "ldp.msg.tlv.sess.atm.minvci", FT_UINT16, BASE_DEC, NULL, 0x0, "Minimum VCI", HFILL }},
{ &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 }},
{ &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 }},
{ &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 }},
{ &hf_ldp_tlv_sess_fr_dir,
{ "Directionality", "ldp.msg.tlv.sess.fr.dir", FT_BOOLEAN, 8, TFS(&tlv_atm_dirbit), 0x02, "Lablel Directionality", HFILL }},
{ &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 }},
{ &hf_ldp_tlv_sess_fr_mindlci,
{ "Minimum DLCI", "ldp.msg.tlv.sess.fr.mindlci", FT_UINT24, BASE_DEC, NULL, 0x7FFFFF, "Minimum DLCI", HFILL }},
{ &hf_ldp_tlv_sess_fr_maxdlci,
{ "Maximum DLCI", "ldp.msg.tlv.sess.fr.maxdlci", FT_UINT24, BASE_DEC, NULL, 0x7FFFFF, "Maximum DLCI", HFILL }},
{ &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 }},
{ &hf_ldp_tlv_vendor_id,
{ "Vendor ID", "ldp.msg.tlv.vendor_id", FT_UINT32, BASE_HEX, NULL, 0, "IEEE 802 Assigned Vendor ID", HFILL }},
{ &hf_ldp_tlv_experiment_id,
{ "Experiment ID", "ldp.msg.tlv.experiment_id", FT_UINT32, BASE_HEX, NULL, 0, "Experiment ID", HFILL }},
{ &hf_ldp_tlv_generic_label,
{ "Generic Label", "ldp.msg.tlv.generic.label", FT_UINT32, BASE_HEX, NULL, 0x000FFFFF, "Generic Label", 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_tlv_atm_label_vpi,
{ "VPI", "ldp.msg.tlv.atm.label.vpi", FT_UINT16, BASE_DEC, NULL, 0x0FFF, "ATM Label VPI", 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_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_tlv_fr_label_dlci,
{ "DLCI", "ldp.msg.tlv.fr.label.dlci", FT_UINT24, BASE_DEC, NULL, 0x7FFFFF, "FRAME RELAY Label DLCI", 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_tlv_status_fbit,
{ "F Bit", "ldp.msg.tlv.status.fbit", FT_BOOLEAN, 8, TFS(&tlv_status_fbit), 0x40, "Forward Bit", 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_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_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_extstatus_data,
{ "Extended Status Data", "ldp.msg.tlv.extstatus.data", FT_UINT32, BASE_HEX, NULL, 0x0, "Extended Status Data", 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_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_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_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_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_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_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_returned_msg_id,
{ "Returned Message ID", "ldp.msg.tlv.returned.msg.id", FT_UINT32, BASE_HEX, NULL, 0x0, "LDP Message ID", HFILL }},
{&hf_ldp_tlv_fec_vc_controlword,
{"C-bit", "ldp.msg.tlv.fec.vc.controlword", FT_BOOLEAN, 8, TFS(&fec_vc_cbit), 0x80, "Control Word Present", HFILL }},
{&hf_ldp_tlv_fec_vc_vctype,
{"VC Type", "ldp.msg.tlv.fec.vc.vctype", FT_UINT16, BASE_HEX, VALS(fec_vc_types_vals), 0x7FFF, "Virtual Circuit Type", HFILL }},
{&hf_ldp_tlv_fec_vc_infolength,
{"VC Info Length", "ldp.msg.tlv.fec.vc.infolength", FT_UINT8, BASE_DEC, NULL, 0x0, "VC FEC Info Length", HFILL }},
{&hf_ldp_tlv_fec_vc_groupid,
{"Group ID", "ldp.msg.tlv.fec.vc.groupid", FT_UINT32, BASE_DEC, NULL, 0x0, "VC FEC Group ID", HFILL }},
{&hf_ldp_tlv_fec_vc_vcid,
{"VC ID", "ldp.msg.tlv.fec.vc.vcid", FT_UINT32, BASE_DEC, NULL, 0x0, "VC FEC VCID", HFILL }},
{&hf_ldp_tlv_fec_vc_intparam_length,
{"Length", "ldp.msg.tlv.fec.vc.intparam.length", FT_UINT8, BASE_DEC, NULL, 0x0, "VC FEC Interface Paramater Length", HFILL }},
{&hf_ldp_tlv_fec_vc_intparam_mtu,
{"MTU", "ldp.msg.tlv.fec.vc.intparam.mtu", FT_UINT16, BASE_DEC, NULL, 0x0, "VC FEC Interface Paramater MTU", HFILL }},
{&hf_ldp_tlv_fec_vc_intparam_id,
{"ID", "ldp.msg.tlv.fec.vc.intparam.id", FT_UINT8, BASE_HEX, VALS(fec_vc_interfaceparm), 0x0, "VC FEC Interface Paramater ID", HFILL }},
{&hf_ldp_tlv_fec_vc_intparam_maxcatmcells,
{"Number of Cells", "ldp.msg.tlv.fec.vc.intparam.maxatm", FT_UINT16, BASE_DEC, NULL, 0x0, "VC FEC Interface Param Max ATM Concat Cells", HFILL }},
{ &hf_ldp_tlv_fec_vc_intparam_desc,
{ "Description", "ldp.msg.tlv.fec.vc.intparam.desc", FT_STRING, BASE_DEC, NULL, 0, "VC FEC Interface Description", HFILL }},
{&hf_ldp_tlv_fec_vc_intparam_cembytes,
{"Payload Bytes", "ldp.msg.tlv.fec.vc.intparam.cembytes", FT_UINT16, BASE_DEC, NULL, 0x0, "VC FEC Interface Param CEM Payload Bytes", HFILL }},
};
static gint *ett[] = {
&ett_ldp,
&ett_ldp_header,
&ett_ldp_ldpid,
&ett_ldp_message,
&ett_ldp_tlv,
&ett_ldp_tlv_val,
&ett_ldp_fec,
&ett_ldp_fec_vc_interfaceparam
};
module_t *ldp_module;
proto_ldp = proto_register_protocol("Label Distribution Protocol",
"LDP", "ldp");
proto_register_field_array(proto_ldp, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
/* Register our configuration options for , particularly our port */
ldp_module = prefs_register_protocol(proto_ldp, proto_reg_handoff_ldp);
prefs_register_uint_preference(ldp_module, "tcp.port", "LDP TCP Port",
"Set the TCP port for messages (if other"
" than the default of 646)",
10, &global_ldp_tcp_port);
prefs_register_uint_preference(ldp_module, "udp.port", "LDP UDP Port",
"Set the UDP port for messages (if other"
" 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 */
void
proto_reg_handoff_ldp(void)
{
static int ldp_prefs_initialized = FALSE;
static dissector_handle_t ldp_tcp_handle, ldp_handle;
if (!ldp_prefs_initialized) {
ldp_tcp_handle = create_dissector_handle(dissect_ldp_tcp, proto_ldp);
ldp_handle = create_dissector_handle(dissect_ldp, proto_ldp);
ldp_prefs_initialized = TRUE;
}
else {
dissector_delete("tcp.port", tcp_port, ldp_tcp_handle);
dissector_delete("udp.port", udp_port, ldp_handle);
}
/* Set our port number for future use */
tcp_port = global_ldp_tcp_port;
udp_port = global_ldp_udp_port;
dissector_add("tcp.port", global_ldp_tcp_port, ldp_tcp_handle);
dissector_add("udp.port", global_ldp_udp_port, ldp_handle);
}