diff options
author | etxrab <etxrab@f5534014-38df-0310-8fa8-9805f1628bb7> | 2009-06-29 19:24:14 +0000 |
---|---|---|
committer | etxrab <etxrab@f5534014-38df-0310-8fa8-9805f1628bb7> | 2009-06-29 19:24:14 +0000 |
commit | 3e10a76d7be7ad82fc7cd157e7f19eb89af40432 (patch) | |
tree | 36b9053c7004578238521b8d0194f95c171c44e9 /epan/dissectors | |
parent | ec142a139ba3f3710421d42e79c5a21ed6a23cc1 (diff) |
From Artem Tamazov:
Added: PW ATM 1:1, AAL5 SDU, AAL5 PDU support + BFD fix + PW ATM OAM fix
git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@28881 f5534014-38df-0310-8fa8-9805f1628bb7
Diffstat (limited to 'epan/dissectors')
-rw-r--r-- | epan/dissectors/Makefile.common | 1 | ||||
-rw-r--r-- | epan/dissectors/packet-atm.c | 234 | ||||
-rw-r--r-- | epan/dissectors/packet-atm.h | 4 | ||||
-rw-r--r-- | epan/dissectors/packet-bfd.c | 1 | ||||
-rw-r--r-- | epan/dissectors/packet-mpls.c | 176 | ||||
-rw-r--r-- | epan/dissectors/packet-pw-atm.c | 2418 | ||||
-rw-r--r-- | epan/dissectors/packet-pw-atm.h | 101 | ||||
-rw-r--r-- | epan/dissectors/packet-pw-cesopsn.c | 26 | ||||
-rw-r--r-- | epan/dissectors/packet-pw-common.c | 72 | ||||
-rw-r--r-- | epan/dissectors/packet-pw-common.h | 18 | ||||
-rw-r--r-- | epan/dissectors/packet-pw-satop.c | 28 |
11 files changed, 2410 insertions, 669 deletions
diff --git a/epan/dissectors/Makefile.common b/epan/dissectors/Makefile.common index 59a9cbdb06..092b939398 100644 --- a/epan/dissectors/Makefile.common +++ b/epan/dissectors/Makefile.common @@ -1151,6 +1151,7 @@ DISSECTOR_INCLUDES = \ packet-ppi.h \ packet-ppp.h \ packet-pres.h \ + packet-pw-atm.h \ packet-pw-common.h \ packet-q931.h \ packet-q932.h \ diff --git a/epan/dissectors/packet-atm.c b/epan/dissectors/packet-atm.c index e4585a1479..cc301de2b0 100644 --- a/epan/dissectors/packet-atm.c +++ b/epan/dissectors/packet-atm.c @@ -39,6 +39,7 @@ #include "packet-tr.h" #include "packet-llc.h" #include "prefs.h" +#include "packet-pw-atm.h" static int proto_atm = -1; static int hf_atm_aal = -1; @@ -50,7 +51,6 @@ static int proto_ilmi = -1; static int proto_aal1 = -1; static int proto_aal3_4 = -1; static int proto_oamaal = -1; -static int proto_atm_4717 = -1; static gint ett_atm = -1; static gint ett_atm_lane = -1; @@ -934,6 +934,13 @@ dissect_reassembled_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, tvbuff_t *next_tvb; guint32 crc; guint32 calc_crc; + /* + * ATM dissector is used as "sub-dissector" for ATM pseudowires. + * In such cases, pinfo->private_data is used to pass info from/to + * PW dissector to ATM dissector. For decoding normal ATM traffic + * private_data should be NULL. + */ + gboolean pseudowire_mode = (NULL != pinfo->private_data); /* * This is reassembled traffic, so the cell headers are missing; @@ -965,20 +972,21 @@ dissect_reassembled_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, break; } } - proto_tree_add_uint(atm_tree, hf_atm_vpi, tvb, 0, 0, + if (!pseudowire_mode) { + proto_tree_add_uint(atm_tree, hf_atm_vpi, tvb, 0, 0, pinfo->pseudo_header->atm.vpi); - proto_tree_add_uint(atm_tree, hf_atm_vci, tvb, 0, 0, + proto_tree_add_uint(atm_tree, hf_atm_vci, tvb, 0, 0, pinfo->pseudo_header->atm.vci); - /* Also show vpi/vci in info column */ - if (check_col(pinfo->cinfo, COL_INFO)) - { + /* Also show vpi/vci in info column */ + if (check_col(pinfo->cinfo, COL_INFO)) + { col_append_fstr(pinfo->cinfo, COL_INFO, " VPI=%u, VCI=%u", pinfo->pseudo_header->atm.vpi, pinfo->pseudo_header->atm.vci); + } } - next_tvb = tvb; if (truncated) { /* @@ -1120,7 +1128,13 @@ dissect_reassembled_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, tvb_memcpy(next_tvb, octet, 0, sizeof(octet)); decoded = TRUE; - if ((pntohs(octet) & 0xff) == PPP_IP) + if (octet[0] == 0xaa + && octet[1] == 0xaa + && octet[2] == 0x03) /* LLC SNAP as per RFC2684 */ + { + call_dissector(llc_handle, next_tvb, pinfo, tree); + } + else if ((pntohs(octet) & 0xff) == PPP_IP) { call_dissector(ppp_handle, next_tvb, pinfo, tree); } @@ -1413,13 +1427,14 @@ get_header_err(const guint8 *cell_header) return UNCORRECTIBLE_ERROR; } -static const value_string pt_vals[] = { +const value_string atm_pt_vals[] = { { 0, "User data cell, congestion not experienced, SDU-type = 0" }, { 1, "User data cell, congestion not experienced, SDU-type = 1" }, { 2, "User data cell, congestion experienced, SDU-type = 0" }, { 3, "User data cell, congestion experienced, SDU-type = 1" }, { 4, "Segment OAM F5 flow related cell" }, { 5, "End-to-end OAM F5 flow related cell" }, + { 6, "VC resource management cell" }, { 0, NULL } }; @@ -1522,6 +1537,19 @@ static const value_string ft_ad_vals[] = { { 0, NULL } }; + +/* + * Check for OAM cells. + * OAM F4 is VCI 3 or 4 and PT 0X0. + * OAM F5 is PT 10X. + */ +gboolean atm_is_oam_cell(const guint16 vci, const guint8 pt) +{ + return (((vci == 3 || vci == 4) && ((pt & 0x5) == 0)) + || ((pt & 0x6) == 0x4)); +} + + static void dissect_atm_cell(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_tree *atm_tree, guint aal, gboolean nni, @@ -1540,8 +1568,10 @@ dissect_atm_cell(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint length; guint16 crc10; tvbuff_t *next_tvb; + const pwatm_private_data_t * pwpd = pinfo->private_data; - if (!nni) { + if (NULL == pwpd) { + if (!nni) { /* * FF: ITU-T I.361 (Section 2.2) defines the cell header format * and encoding at UNI reference point as: @@ -1565,7 +1595,7 @@ dissect_atm_cell(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, octet = tvb_get_guint8(tvb, 1); vpi |= octet >> 4; proto_tree_add_uint(atm_tree, hf_atm_vpi, tvb, 0, 2, vpi); - } else { + } else { /* * FF: ITU-T I.361 (Section 2.3) defines the cell header format * and encoding at NNI reference point as: @@ -1588,21 +1618,21 @@ dissect_atm_cell(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, octet = tvb_get_guint8(tvb, 1); vpi |= (octet & 0xF0) >> 4; proto_tree_add_uint(atm_tree, hf_atm_vpi, tvb, 0, 2, vpi); - } + } - vci = (octet & 0x0F) << 12; - octet = tvb_get_guint8(tvb, 2); - vci |= octet << 4; - octet = tvb_get_guint8(tvb, 3); - vci |= octet >> 4; - proto_tree_add_uint(atm_tree, hf_atm_vci, tvb, 1, 3, vci); - pt = (octet >> 1) & 0x7; - proto_tree_add_text(atm_tree, tvb, 3, 1, "Payload Type: %s", - val_to_str(pt, pt_vals, "Unknown (%u)")); - proto_tree_add_text(atm_tree, tvb, 3, 1, "Cell Loss Priority: %s", + vci = (octet & 0x0F) << 12; + octet = tvb_get_guint8(tvb, 2); + vci |= octet << 4; + octet = tvb_get_guint8(tvb, 3); + vci |= octet >> 4; + proto_tree_add_uint(atm_tree, hf_atm_vci, tvb, 1, 3, vci); + pt = (octet >> 1) & 0x7; + proto_tree_add_text(atm_tree, tvb, 3, 1, "Payload Type: %s", + val_to_str(pt, atm_pt_vals, "Unknown (%u)")); + proto_tree_add_text(atm_tree, tvb, 3, 1, "Cell Loss Priority: %s", (octet & 0x01) ? "Low priority" : "High priority"); - - if (!crc_stripped) { + + if (!crc_stripped) { /* * FF: parse the Header Error Check (HEC). */ @@ -1617,13 +1647,22 @@ dissect_atm_cell(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, else proto_item_append_text(ti, " (error in bit %d)", err); offset = 5; - } else { + } else { /* * FF: in some encapsulation modes (e.g. RFC 4717, ATM N-to-One * Cell Mode) the Header Error Check (HEC) field is stripped. * So we do nothing here. */ offset = 4; + } + } + else + { + offset = 0; /* For PWs. Header is decoded by PW dissector.*/ + pwpd = pinfo->private_data; + vpi = pwpd->vpi; + vci = pwpd->vci; + pt = pwpd->pti; } /* @@ -1632,13 +1671,9 @@ dissect_atm_cell(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, * Wiretap got from the file? */ if (aal == AAL_USER) { - /* - * OAM F4 is VCI 3 or 4 and PT 0X0. - * OAM F5 is PT 10X. - */ - if (((vci == 3 || vci == 4) && ((pt & 0x5) == 0)) || - ((pt & 0x6) == 0x4)) - aal = AAL_OAMCELL; + if (atm_is_oam_cell(vci,pt)) { + aal = AAL_OAMCELL; + } } switch (aal) { @@ -1706,16 +1741,22 @@ dissect_atm_cell(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, break; case AAL_OAMCELL: - if (check_col(pinfo->cinfo, COL_PROTOCOL)) - col_set_str(pinfo->cinfo, COL_PROTOCOL, "OAM AAL"); - if (check_col(pinfo->cinfo, COL_INFO)) - col_clear(pinfo->cinfo, COL_INFO); + if (NULL == pwpd || pwpd->enable_fill_columns_by_atm_dissector) + { + if (check_col(pinfo->cinfo, COL_PROTOCOL)) + col_set_str(pinfo->cinfo, COL_PROTOCOL, "OAM AAL"); + if (check_col(pinfo->cinfo, COL_INFO)) + col_clear(pinfo->cinfo, COL_INFO); + } ti = proto_tree_add_item(tree, proto_oamaal, tvb, offset, -1, FALSE); aal_tree = proto_item_add_subtree(ti, ett_oamaal); octet = tvb_get_guint8(tvb, offset); - if (check_col(pinfo->cinfo, COL_INFO)) - col_add_fstr(pinfo->cinfo, COL_INFO, "%s", + if (NULL == pwpd || pwpd->enable_fill_columns_by_atm_dissector) + { + if (check_col(pinfo->cinfo, COL_INFO)) + col_add_fstr(pinfo->cinfo, COL_INFO, "%s", val_to_str(octet >> 4, oam_type_vals, "Unknown (%u)")); + } proto_tree_add_text(aal_tree, tvb, offset, 1, "OAM Type: %s", val_to_str(octet >> 4, oam_type_vals, "Unknown (%u)")); switch (octet >> 4) { @@ -1767,6 +1808,7 @@ dissect_atm_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, { proto_tree *atm_tree = NULL; proto_item *atm_ti = NULL; + gboolean pseudowire_mode = (NULL != pinfo->private_data); if ( pinfo->pseudo_header->atm.aal == AAL_5 && pinfo->pseudo_header->atm.type == TRAF_LANE && @@ -1777,23 +1819,25 @@ dissect_atm_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, if (check_col(pinfo->cinfo, COL_PROTOCOL)) col_set_str(pinfo->cinfo, COL_PROTOCOL, "ATM"); - switch (pinfo->pseudo_header->atm.channel) { + if (!pseudowire_mode) { + switch (pinfo->pseudo_header->atm.channel) { - case 0: - /* Traffic from DTE to DCE. */ - if (check_col(pinfo->cinfo, COL_RES_DL_DST)) - col_set_str(pinfo->cinfo, COL_RES_DL_DST, "DCE"); - if (check_col(pinfo->cinfo, COL_RES_DL_SRC)) - col_set_str(pinfo->cinfo, COL_RES_DL_SRC, "DTE"); - break; + case 0: + /* Traffic from DTE to DCE. */ + if (check_col(pinfo->cinfo, COL_RES_DL_DST)) + col_set_str(pinfo->cinfo, COL_RES_DL_DST, "DCE"); + if (check_col(pinfo->cinfo, COL_RES_DL_SRC)) + col_set_str(pinfo->cinfo, COL_RES_DL_SRC, "DTE"); + break; - case 1: - /* Traffic from DCE to DTE. */ - if (check_col(pinfo->cinfo, COL_RES_DL_DST)) - col_set_str(pinfo->cinfo, COL_RES_DL_DST, "DTE"); - if (check_col(pinfo->cinfo, COL_RES_DL_SRC)) - col_set_str(pinfo->cinfo, COL_RES_DL_SRC, "DCE"); - break; + case 1: + /* Traffic from DCE to DTE. */ + if (check_col(pinfo->cinfo, COL_RES_DL_DST)) + col_set_str(pinfo->cinfo, COL_RES_DL_DST, "DTE"); + if (check_col(pinfo->cinfo, COL_RES_DL_SRC)) + col_set_str(pinfo->cinfo, COL_RES_DL_SRC, "DCE"); + break; + } } if (check_col(pinfo->cinfo, COL_INFO)) { @@ -1812,23 +1856,25 @@ dissect_atm_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, atm_ti = proto_tree_add_protocol_format(tree, proto_atm, tvb, 0, 0, "ATM"); atm_tree = proto_item_add_subtree(atm_ti, ett_atm); - switch (pinfo->pseudo_header->atm.channel) { + if (!pseudowire_mode) { + switch (pinfo->pseudo_header->atm.channel) { - case 0: - /* Traffic from DTE to DCE. */ - proto_tree_add_text(atm_tree, tvb, 0, 0, "Channel: DTE->DCE"); - break; + case 0: + /* Traffic from DTE to DCE. */ + proto_tree_add_text(atm_tree, tvb, 0, 0, "Channel: DTE->DCE"); + break; - case 1: - /* Traffic from DCE to DTE. */ - proto_tree_add_text(atm_tree, tvb, 0, 0, "Channel: DCE->DTE"); - break; + case 1: + /* Traffic from DCE to DTE. */ + proto_tree_add_text(atm_tree, tvb, 0, 0, "Channel: DCE->DTE"); + break; - default: - /* Sniffers shouldn't provide anything other than 0 or 1. */ - proto_tree_add_text(atm_tree, tvb, 0, 0, "Channel: %u", + default: + /* Sniffers shouldn't provide anything other than 0 or 1. */ + proto_tree_add_text(atm_tree, tvb, 0, 0, "Channel: %u", pinfo->pseudo_header->atm.channel); - break; + break; + } } proto_tree_add_uint_format_value(atm_tree, hf_atm_aal, tvb, 0, 0, @@ -1865,59 +1911,21 @@ dissect_atm_oam_cell(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *atm_tree = NULL; proto_item *atm_ti = NULL; + gboolean pseudowire_mode = (NULL != pinfo->private_data); if (check_col(pinfo->cinfo, COL_PROTOCOL)) col_set_str(pinfo->cinfo, COL_PROTOCOL, "ATM"); - if (tree) { - atm_ti = proto_tree_add_protocol_format(tree, proto_atm, tvb, 0, 0, "ATM"); - atm_tree = proto_item_add_subtree(atm_ti, ett_atm); + if (!pseudowire_mode) { + if (tree) { + atm_ti = proto_tree_add_protocol_format(tree, proto_atm, tvb, 0, 0, "ATM"); + atm_tree = proto_item_add_subtree(atm_ti, ett_atm); + } } dissect_atm_cell(tvb, pinfo, tree, atm_tree, AAL_OAMCELL, FALSE, FALSE); } -/* - * FF: this dissector is called directly from packet-pw-atm.c. - * it checks pinfo->pw_atm_encap_type, pinfo->pw_atm_flags - * in order to gather information about the used encapsulation - * format (defined in RFC 4717). The result (i.e. protocol tree - * and cinfo) of this dissector should look like, as close as - * possible, to the legacy one (i.e. dissect_atm_[untruncated|oam_cell]). - */ -static void -dissect_atm_4717(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) -{ - proto_tree *atm_tree = NULL; - proto_item *atm_ti = NULL; - - if (check_col(pinfo->cinfo, COL_PROTOCOL)) - col_set_str(pinfo->cinfo, COL_PROTOCOL, "ATM"); - - if (tree) { - atm_ti = proto_tree_add_protocol_format(tree, - proto_atm, - tvb, 0, 0, "ATM"); - atm_tree = proto_item_add_subtree(atm_ti, ett_atm); - } - - switch (pinfo->pw_atm_encap_type) { - case 1: /* ATM N-to-One Cell Mode */ - if (check_col(pinfo->cinfo, COL_INFO)) { - col_add_str(pinfo->cinfo, COL_INFO, "Unknown AAL"); - col_append_fstr(pinfo->cinfo, COL_INFO, - " (%u cell%s)", - pinfo->pw_atm_ncells, - pinfo->pw_atm_ncells == 1 ? "" : "s"); - } - proto_item_set_len(atm_ti, 4); - dissect_atm_cell(tvb, pinfo, tree, atm_tree, - AAL_UNKNOWN, TRUE, TRUE); - break; - default: - break; - } -} void proto_register_atm(void) @@ -1971,8 +1979,8 @@ proto_register_atm(void) register_dissector("lane", dissect_lane, proto_atm_lane); register_dissector("atm_untruncated", dissect_atm_untruncated, proto_atm); + register_dissector("atm_truncated", dissect_atm, proto_atm); register_dissector("atm_oam_cell", dissect_atm_oam_cell, proto_oamaal); - register_dissector("atm_4717", dissect_atm_4717, proto_atm_4717); atm_module = prefs_register_protocol ( proto_atm, NULL ); prefs_register_bool_preference ( atm_module, "dissect_lane_as_sscop", "Dissect LANE as SSCOP", @@ -1983,7 +1991,7 @@ proto_register_atm(void) void proto_reg_handoff_atm(void) { - dissector_handle_t atm_handle, atm_untruncated_handle, atm_4717_handle; + dissector_handle_t atm_handle, atm_untruncated_handle; /* * Get handles for the Ethernet, Token Ring, Frame Relay, LLC, @@ -2009,6 +2017,4 @@ proto_reg_handoff_atm(void) proto_atm); dissector_add("wtap_encap", WTAP_ENCAP_ATM_PDUS_UNTRUNCATED, atm_untruncated_handle); - - atm_4717_handle = create_dissector_handle(dissect_atm_4717, proto_atm); } diff --git a/epan/dissectors/packet-atm.h b/epan/dissectors/packet-atm.h index 2c6f04213a..466d54972a 100644 --- a/epan/dissectors/packet-atm.h +++ b/epan/dissectors/packet-atm.h @@ -27,4 +27,8 @@ void capture_atm(const union wtap_pseudo_header *, const guchar *, int, packet_counts *); +gboolean atm_is_oam_cell(const guint16 vci, const guint8 pt); /*For pw-atm dissector*/ + +extern const value_string atm_pt_vals[]; /*For pw-atm dissector*/ + #endif diff --git a/epan/dissectors/packet-bfd.c b/epan/dissectors/packet-bfd.c index 2b82c4237e..7d564a26ac 100644 --- a/epan/dissectors/packet-bfd.c +++ b/epan/dissectors/packet-bfd.c @@ -685,6 +685,7 @@ void proto_register_bfd(void) proto_bfd = proto_register_protocol("Bidirectional Forwarding Detection Control Message", "BFD Control", "bfd"); + register_dissector("bfd", dissect_bfd_control, proto_bfd); /* Required function calls to register the header fields and subtrees used */ proto_register_field_array(proto_bfd, hf, array_length(hf)); diff --git a/epan/dissectors/packet-mpls.c b/epan/dissectors/packet-mpls.c index 024fbe0d4f..6d77b1e803 100644 --- a/epan/dissectors/packet-mpls.c +++ b/epan/dissectors/packet-mpls.c @@ -58,6 +58,7 @@ #include <epan/addr_resolv.h> #include "packet-ppp.h" #include "packet-mpls.h" +#include "packet-pw-common.h" static gint proto_mpls = -1; static gint proto_pw_ach = -1; @@ -92,6 +93,7 @@ enum mpls_filter_keys { static dissector_handle_t dissector_data; static dissector_handle_t dissector_ipv6; static dissector_handle_t dissector_ip; +static dissector_handle_t dissector_bfd; static dissector_handle_t dissector_pw_eth_heuristic; static dissector_handle_t dissector_pw_fr; static dissector_handle_t dissector_pw_hdlc_nocw_fr; @@ -100,6 +102,10 @@ static dissector_handle_t dissector_pw_eth_cw; static dissector_handle_t dissector_pw_eth_nocw; static dissector_handle_t dissector_pw_satop; static dissector_handle_t dissector_itdm; +static dissector_handle_t dissector_mpls_pw_atm_n1_cw; +static dissector_handle_t dissector_mpls_pw_atm_n1_nocw; +static dissector_handle_t dissector_mpls_pw_atm_11_aal5pdu; +static dissector_handle_t dissector_mpls_pw_atm_aal5_sdu; static dissector_handle_t dissector_pw_cesopsn; enum mpls_default_dissector_t { @@ -113,6 +119,10 @@ enum mpls_default_dissector_t { ,MDD_MPLS_PW_ETH_NOCW ,MDD_MPLS_PW_GENERIC ,MDD_ITDM + ,MDD_MPLS_PW_ATM_N1_CW + ,MDD_MPLS_PW_ATM_N1_NOCW + ,MDD_MPLS_PW_ATM_11_OR_AAL5_PDU + ,MDD_MPLS_PW_ATM_AAL5_SDU }; /* TODO the content of mpls_default_payload menu @@ -123,12 +133,12 @@ enum mpls_default_dissector_t { static enum_val_t mpls_default_payload_defs[] = { { "pw satop" - ,"SAToP (no RTP support)" + ,pwc_longname_pw_satop ,MDD_PW_SATOP }, { "pw cesopsn" - ,"CESoPSN basic NxDS0 mode (no RTP support)" + ,pwc_longname_pw_cesopsn ,MDD_PW_CESOPSN }, { @@ -172,6 +182,26 @@ static enum_val_t mpls_default_payload_defs[] = { ,MDD_ITDM }, { + "mpls pw atm n_to_one cw" + ,pwc_longname_pw_atm_n1_cw + ,MDD_MPLS_PW_ATM_N1_CW + }, + { + "mpls pw atm n_to_one no_cw" + ,pwc_longname_pw_atm_n1_nocw + ,MDD_MPLS_PW_ATM_N1_NOCW + }, + { + "mpls pw atm one_to_one or aal5_pdu" + ,pwc_longname_pw_atm_11_or_aal5_pdu + ,MDD_MPLS_PW_ATM_11_OR_AAL5_PDU + }, + { + "mpls pw atm aal5_sdu" + ,pwc_longname_pw_atm_aal5_sdu + ,MDD_MPLS_PW_ATM_AAL5_SDU + }, + { NULL ,NULL ,-1 @@ -181,6 +211,9 @@ static enum_val_t mpls_default_payload_defs[] = { static int mpls_filter[MPLSF_MAX]; static gint mpls_default_payload = 0; +static gboolean mpls_pref_pwac_all_as_bfd_xipv4 = FALSE; +static gboolean mpls_pref_pwac_0x0_as_bfd = FALSE; +static gboolean mpls_pref_pwac_try_ppp = TRUE; static int hf_mpls_1st_nibble = -1; @@ -236,6 +269,60 @@ static const value_string oam_defect_type_vals[] = { {0, NULL } }; +#if 0 /*not used yet*/ +/* + * MPLS PW types + * http://www.iana.org/assignments/pwe3-parameters + */ +static const value_string mpls_pw_types[] = { + { 0x0001, "Frame Relay DLCI ( Martini Mode )" }, + { 0x0002, "ATM AAL5 SDU VCC transport" }, + { 0x0003, "ATM transparent cell transport" }, + { 0x0004, "Ethernet Tagged Mode" }, + { 0x0005, "Ethernet" }, + { 0x0006, "HDLC" }, + { 0x0007, "PPP" }, + { 0x0008, "SONET/SDH Circuit Emulation Service Over MPLS" }, + { 0x0009, "ATM n-to-one VCC cell transport" }, + { 0x000A, "ATM n-to-one VPC cell transport" }, + { 0x000B, "IP Layer2 Transport" }, + { 0x000C, "ATM one-to-one VCC Cell Mode" }, + { 0x000D, "ATM one-to-one VPC Cell Mode" }, + { 0x000E, "ATM AAL5 PDU VCC transport" }, + { 0x000F, "Frame-Relay Port mode" }, + { 0x0010, "SONET/SDH Circuit Emulation over Packet" }, + { 0x0011, "Structure-agnostic E1 over Packet" }, + { 0x0012, "Structure-agnostic T1 (DS1) over Packet" }, + { 0x0013, "Structure-agnostic E3 over Packet" }, + { 0x0014, "Structure-agnostic T3 (DS3) over Packet" }, + { 0x0015, "CESoPSN basic mode" }, + { 0x0016, "TDMoIP AAL1 Mode" }, + { 0x0017, "CESoPSN TDM with CAS" }, + { 0x0018, "TDMoIP AAL2 Mode" }, + { 0x0019, "Frame Relay DLCI" }, + { 0x001A, "ROHC Transport Header-compressed Packets" },/*[RFC4995][RFC4901]*/ + { 0x001B, "ECRTP Transport Header-compressed Packets" },/*[RFC3545][RFC4901]*/ + { 0x001C, "IPHC Transport Header-compressed Packets" },/*[RFC2507][RFC4901]*/ + { 0x001D, "cRTP Transport Header-compressed Packets" },/*[RFC2508][RFC4901]*/ + { 0x001E, "ATM VP Virtual Trunk" },/*[MFA9]*/ + { 0x001F, "Reserved" },/*[Bryant] 2008-04-17*/ + { 0, NULL } +}; +#endif + +/* + * MPLS PW Associated Channel Types + * as per http://www.iana.org/assignments/pwe3-parameters + * and http://tools.ietf.org/html/draft-ietf-pwe3-vccv-bfd-05 clause 3.2 + */ +static const value_string mpls_pwac_types[] = { + { 0x0007, "BFD Control, PW-ACH-encapsulated (BFD Without IP/UDP Headers)" }, + { 0x0021, "IPv4 packet" }, + { 0x0057, "IPv6 packet" }, + { 0, NULL } +}; + + static dissector_table_t ppp_subdissector_table; static dissector_table_t mpls_subdissector_table; @@ -289,20 +376,49 @@ dissect_pw_ach(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) tvb, 0, 1, ver, "Version: %d", ver); ti = proto_tree_add_uint_format(mpls_pw_ach_tree, hf_mpls_pw_ach_res, tvb, 1, 1, res, "Reserved: 0x%02x", res); - PROTO_ITEM_SET_HIDDEN(ti); if (res != 0) proto_tree_add_text(mpls_pw_ach_tree, tvb, 1, 1, "Error: this byte is reserved and must be 0"); + else + PROTO_ITEM_SET_HIDDEN(ti); proto_tree_add_uint_format(mpls_pw_ach_tree, hf_mpls_pw_ach_channel_type, tvb, 2, 2, channel_type, "Channel Type: %s (0x%04x)", - val_to_str(channel_type, ppp_vals, "Unknown"), + val_to_str(channel_type, mpls_pwac_types, "Unknown"), channel_type); } next_tvb = tvb_new_subset(tvb, 4, -1, -1); - if (!dissector_try_port(ppp_subdissector_table, channel_type, + + if (0x21 == channel_type /*IPv4, RFC4385 clause 6.*/) + { + call_dissector(dissector_ip, next_tvb, pinfo, tree); + } + else if (0x7 == channel_type /*PWACH-encapsulated BFD, draft-ietf-pwe3-vccv-bfd-05 3.2*/ + || mpls_pref_pwac_all_as_bfd_xipv4) + { + call_dissector(dissector_bfd, next_tvb, pinfo, tree); + } + else if (0x57 == channel_type /*IPv6, RFC4385 clause 6.*/) + { + call_dissector(dissector_ipv6, next_tvb, pinfo, tree); + } + else if (0x0 == channel_type && mpls_pref_pwac_0x0_as_bfd) + { + call_dissector(dissector_bfd, next_tvb, pinfo, tree); + } + else if (mpls_pref_pwac_try_ppp) + { + /* XXX perhaps this code should be reconsidered */ + /* non-standard extension, therefore controlled by option*/ + /* appeared in revision 10862 from Carlos M. Pignataro */ + if (!dissector_try_port(ppp_subdissector_table, channel_type, next_tvb, pinfo, tree)) { call_dissector(dissector_data, next_tvb, pinfo, tree); + } + } + else + { + call_dissector(dissector_data, next_tvb, pinfo, tree); } } @@ -683,8 +799,20 @@ dissect_mpls(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) case MDD_ITDM: call_dissector(dissector_itdm, next_tvb, pinfo, tree); break; - default: /*fallthrough*/ - case MDD_MPLS_PW_GENERIC: + case MDD_MPLS_PW_ATM_N1_CW: + call_dissector(dissector_mpls_pw_atm_n1_cw, next_tvb, pinfo, tree); + break; + case MDD_MPLS_PW_ATM_N1_NOCW: + call_dissector(dissector_mpls_pw_atm_n1_nocw, next_tvb, pinfo, tree); + break; + case MDD_MPLS_PW_ATM_11_OR_AAL5_PDU: + call_dissector(dissector_mpls_pw_atm_11_aal5pdu, next_tvb, pinfo, tree); + break; + case MDD_MPLS_PW_ATM_AAL5_SDU: + call_dissector(dissector_mpls_pw_atm_aal5_sdu, next_tvb, pinfo, tree); + break; + default: /*fallthrough*/ + case MDD_MPLS_PW_GENERIC: dissect_pw_mcw(next_tvb, pinfo, tree); break; } @@ -806,6 +934,35 @@ proto_register_mpls(void) &mpls_default_payload, mpls_default_payload_defs, FALSE ); + prefs_register_bool_preference(module_mpls + ,"mplspref.pwac_0x0_as_bfd" + ,"Assume PWAC Channel Type 0x0 is raw BFD" + ,"draft-ietf-pwe3-vccv-bfd-05 states that PWAC Channel Type 0x07 must be used" + " when VCCV carries PW-ACH-encapsulated BFD (i.e., BFD without IP/UDP Headers, or \"raw\" BFD)" + "\n\n" + "Legacy or buggy devices may not comply to this and use Channel Type 0x0 for BFD." + " Enable this preference to decode such BFD traffic." + " Disable for standard behavior of PWAC dissector (default)." + ,&mpls_pref_pwac_0x0_as_bfd); + prefs_register_bool_preference(module_mpls + ,"mplspref.pwac_all_as_bfd_xip" + ,"Assume that all PWAC Channel Types (except 0x21) are raw BFD" + ,"draft-ietf-pwe3-vccv-bfd-05 states that PWAC Channel Type 0x07 must be used" + " when VCCV carries PW-ACH-encapsulated BFD (i.e., \"raw\" BFD)" + "\n\n" + "Legacy or buggy devices may not comply to this and use voluntary Channel Type for BFD." + " Enable this preference to decode all PWAC Channel Types as raw BFD," + " except Channel Type 0x21 (IPv4)." + " Disable for standard behavior of PWAC dissector (default)." + ,&mpls_pref_pwac_all_as_bfd_xipv4); + prefs_register_bool_preference(module_mpls + ,"mplspref.pwac_try_ppp" + ,"As a last resort, try to decode PWAC payloads as PPP traffic" + ,"Legacy devices may use MPLS PW Associated Channel for PPP traffic." + "\n\n" + "Enable this preference to allow PWAC dissector to try PPP," + " if no other suitable dissector found (default)." + ,&mpls_pref_pwac_try_ppp); } void @@ -836,6 +993,7 @@ proto_reg_handoff_mpls(void) dissector_data = find_dissector("data"); dissector_ipv6 = find_dissector("ipv6"); dissector_ip = find_dissector("ip"); + dissector_bfd = find_dissector("bfd"); dissector_pw_eth_heuristic = find_dissector("pw_eth_heuristic"); dissector_pw_fr = find_dissector("pw_fr"); dissector_pw_hdlc_nocw_fr = find_dissector("pw_hdlc_nocw_fr"); @@ -844,6 +1002,10 @@ proto_reg_handoff_mpls(void) dissector_pw_eth_nocw = find_dissector("pw_eth_nocw"); dissector_pw_satop = find_dissector("pw_satop"); dissector_itdm = find_dissector("itdm"); + dissector_mpls_pw_atm_n1_cw = find_dissector("mpls_pw_atm_n1_cw"); + dissector_mpls_pw_atm_n1_nocw = find_dissector("mpls_pw_atm_n1_nocw"); + dissector_mpls_pw_atm_11_aal5pdu= find_dissector("mpls_pw_atm_11_or_aal5_pdu"); + dissector_mpls_pw_atm_aal5_sdu = find_dissector("mpls_pw_atm_aal5_sdu"); dissector_pw_cesopsn = find_dissector("pw_cesopsn"); initialized = TRUE; diff --git a/epan/dissectors/packet-pw-atm.c b/epan/dissectors/packet-pw-atm.c index c281b70dd5..bec5e81966 100644 --- a/epan/dissectors/packet-pw-atm.c +++ b/epan/dissectors/packet-pw-atm.c @@ -1,9 +1,10 @@ /* packet-pw-atm.c * Routines for ATM PW dissection: it should be conform to RFC 4717. * - * Copyright 2009 _FF_ + * Copyright 2009 _FF_, _ATA_ * * Francesco Fondelli <francesco dot fondelli, gmail dot com> + * Artem Tamazov <artem [dot] tamazov [at] tellabs [dot] com> * * $Id$ * @@ -30,15 +31,9 @@ DONE: - ATM N-to-One Cell Mode (with CW) - ATM N-to-One Cell Mode (no CW) - TODO: - ATM One-to-One Cell Mode - ATM AAL5 SDU Mode - ATM AAL5 PDU Mode - - Please pick an item from the TODO list, move code out of #if 0 - (see below) and implement a dissector for the given encapsulation - mode. The N-to-One Cell Mode is the only mandatory encap - mode. One-to-One/SDU/PDU modes are optional. */ #ifdef HAVE_CONFIG_H @@ -50,541 +45,1968 @@ #include <string.h> #include <glib.h> #include <epan/packet.h> +#include <epan/expert.h> +#include <epan/prefs.h> +#include <wiretap/wtap.h> /*for atm pseudo header*/ #include "packet-mpls.h" +#include "packet-atm.h" +#include "packet-pw-atm.h" +#include "packet-pw-common.h" -static gint proto_pw_atm_n2o_cw = -1; -static gint proto_pw_atm_n2o_nocw = -1; -#if 0 -static gint proto_pw_atm_o2o_cw = -1; -static gint proto_pw_atm_o2o_nocw = -1; -static gint proto_pw_atm_aal5_pdu_cw = -1; -static gint proto_pw_atm_aal5_pdu_nocw = -1; -static gint proto_pw_atm_aal5_sdu_cw = -1; -static gint proto_pw_atm_aal5_sdu_nocw = -1; -#endif +static gint proto_n1_nocw = -1; +static gint proto_n1_cw = -1; +static gint proto_11_or_aal5_pdu = -1; +static gint proto_aal5_sdu = -1; +/* subordinate dissectors: */ +static gint proto_control_word = -1; +static gint proto_cell_header = -1; +static gint proto_cell = -1; -static gint ett_pw_atm = -1; - -static int hf_pw_atm_n2o_cw = -1; -static int hf_pw_atm_n2o_cw_flags = -1; -static int hf_pw_atm_n2o_cw_length = -1; -static int hf_pw_atm_n2o_cw_sequence_number = -1; -static int hf_pw_atm_n2o_nocw = -1; -#if 0 -static int hf_pw_atm_o2o_cw = -1; -static int hf_pw_atm_o2o_cw_sequence_number = -1; -static int hf_pw_atm_o2o_cw_flags = -1; -static int hf_pw_atm_o2o_cw_flags_m = -1; -static int hf_pw_atm_o2o_cw_flags_v = -1; -static int hf_pw_atm_o2o_cw_flags_res = -1; -static int hf_pw_atm_o2o_cw_flags_pti = -1; -static int hf_pw_atm_o2o_cw_flags_c = -1; -static int hf_pw_atm_o2o_nocw = -1; -static int hf_pw_atm_aal5_pdu_cw = -1; -static int hf_pw_atm_aal5_pdu_cw_sequence_number = -1; -static int hf_pw_atm_aal5_pdu_nocw = -1; -static int hf_pw_atm_aal5_sdu_cw = -1; -static int hf_pw_atm_aal5_sdu_cw_sequence_number = -1; -static int hf_pw_atm_aal5_sdu_nocw = -1; -#endif +static gint ett_encaps = -1; +static gint ett_cw = -1; +static gint ett_cell_header = -1; +static gint ett_cell = -1; + +static int hf_pw_type_n1_cw = -1; +static int hf_pw_type_n1_nocw = -1; +static int hf_pw_type_11_vcc = -1; +static int hf_pw_type_11_vpc = -1; +static int hf_pw_type_aal5_sdu = -1; +static int hf_pw_type_aal5_pdu = -1; + +static int hf_cell_h_vpi = -1; +static int hf_cell_h_vci = -1; +static int hf_cell_h_pti = -1; +static int hf_cell_h_clp = -1; +static int hf_cell_h_m = -1; +static int hf_cell_h_v = -1; +static int hf_cell_h_rsv = -1; +static int hf_aal5_pdu_rsv = -1; +static int hf_aal5_pdu_u = -1; +static int hf_aal5_pdu_e = -1; + +static int hf_cw_bits03 = -1; +static int hf_pref_cw_rsv = -1; +static int hf_generic_cw_rsv = -1; +static int hf_pref_cw_flags = -1; +static int hf_pref_cw_a5s_t = -1; +static int hf_pref_cw_a5s_e = -1; +static int hf_pref_cw_a5s_c = -1; +static int hf_pref_cw_a5s_u = -1; +static int hf_pref_cw_len = -1; +static int hf_pref_cw_rsvlen = -1; +static int hf_cw_seq = -1; +static int hf_n1_cw_ncells = -1; +static int hf_n1_nocw_ncells = -1; +static int hf_11_ncells = -1; +static int hf_gen_cw_atmbyte = -1; +static int hf_cell_payload_len = -1; + +static dissector_handle_t dh_cell; +static dissector_handle_t dh_cell_header; +static dissector_handle_t dh_control_word; +static dissector_handle_t dh_atm_truncated; +static dissector_handle_t dh_atm_untruncated; +static dissector_handle_t dh_atm_oam_cell; +static dissector_handle_t dh_padding; +static dissector_handle_t dh_data; + +#define PTI_IS_ADMIN(pti) ((pti) == 4 || (pti) == 5 || (pti) == 6) /*see atm_pt_vals[]*/ + +#define MODE_11(mode) (PWATM_MODE_11_VCC == (mode) || PWATM_MODE_11_VPC == (mode)) +#define MODE_N1(mode) (PWATM_MODE_N1_NOCW == (mode)|| PWATM_MODE_N1_CW == (mode)) +#define MODE_11_OR_AAL5_PDU(mode) (MODE_11(mode) || PWATM_MODE_AAL5_PDU == (mode)) + +#define VALUE_SELECTOR_VPC_VCC_PDU(mode,val_vpc,val_vcc,val_pdu)\ + ((PWATM_MODE_11_VPC == (mode)) \ + ? (val_vpc) \ + : ((PWATM_MODE_11_VCC == (mode)) \ + ? (val_vcc) \ + : ((PWATM_MODE_AAL5_PDU == (mode)) \ + ? (val_pdu) \ + : 0 \ + ) \ + ) \ + ) + +#define UPDATE_CUMULATIVE_VALUE(cumulative_val,new_val)\ + do\ + {\ + if (-2 >= (cumulative_val))\ + {\ + }\ + else if (-1 == (cumulative_val))\ + {\ + (cumulative_val) = (new_val);\ + }\ + else if ((new_val) != (cumulative_val))\ + {\ + (cumulative_val) = -2;\ + }\ + }\ + while(0) + +#define SIZEOF_ATM_CELL_PAYLOAD 48 +#define SIZEOF_N1_PW_CELL_HEADER 4 +#define SIZEOF_11_VCC_PW_CELL_HEADER 1 +#define SIZEOF_11_VPC_PW_CELL_HEADER 3 +#define SIZEOF_N1_PW_CELL (SIZEOF_ATM_CELL_PAYLOAD+SIZEOF_N1_PW_CELL_HEADER) +#define SIZEOF_11_VCC_PW_CELL (SIZEOF_ATM_CELL_PAYLOAD+SIZEOF_11_VCC_PW_CELL_HEADER) +#define SIZEOF_11_VPC_PW_CELL (SIZEOF_ATM_CELL_PAYLOAD+SIZEOF_11_VPC_PW_CELL_HEADER) + +const char pwc_longname_pw_atm_n1_cw[] = "MPLS PW ATM N-to-One encapsulation, with CW"; +const char pwc_longname_pw_atm_n1_nocw[] = "MPLS PW ATM N-to-One encapsulation, no CW"; +const char pwc_longname_pw_atm_11_or_aal5_pdu[] = "MPLS PW ATM One-to-One or AAL5 PDU encapsulation"; +const char pwc_longname_pw_atm_aal5_sdu[] = "MPLS PW ATM AAL5 CPCS-SDU mode encapsulation"; -static dissector_handle_t data_h; -static dissector_handle_t atm_h; +static const char longname_pw_atm_11_vcc[] = "MPLS PW ATM One-to-One VCC Cell Transport"; +static const char longname_pw_atm_11_vpc[] = "MPLS PW ATM One-to-One VPC Cell Transport"; +static const char longname_pw_atm_aal5_pdu[] = "MPLS PW ATM AAL5 PDU encapsulation"; -/* ATM One-to-One Cell Mode bits in "ATM Specific" CW field */ -#define PW_ATM_O2O_CW_M 0x80 -#define PW_ATM_O2O_CW_V 0x40 -#define PW_ATM_O2O_CW_RES 0x30 -#define PW_ATM_O2O_CW_PTI 0x0E -#define PW_ATM_O2O_CW_C 0x01 +static const char shortname_n1_cw[] = "MPLS PW ATM N:1 CW"; +static const char shortname_n1_nocw[] = "MPLS PW ATM N:1 no CW"; +static const char shortname_11_or_aal5_pdu[] = "MPLS PW ATM 1:1 / AAL5 PDU"; +static const char shortname_11_vpc[] = "MPLS PW ATM 1:1 VPC"; +static const char shortname_11_vcc[] = "MPLS PW ATM 1:1 VCC"; +static const char shortname_aal5_sdu[] = "MPLS PW ATM AAL5 SDU"; +static const char shortname_aal5_pdu[] = "MPLS PW ATM AAL5 PDU"; -static void -dissect_pw_atm_n2o_cw(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +/* + * These options are needed to support Nokia AXE and stuff alike. + * Note that these options will affect PW type auto-guessing, if such heuristic + * implemented in the future. + */ +static gboolean pref_n1_cw_allow_cw_length_nonzero = FALSE; +static gboolean pref_n1_cw_extend_cw_length_with_rsvd = FALSE; +static gboolean pref_aal5_sdu_allow_cw_length_nonzero = FALSE; +static gboolean pref_aal5_sdu_extend_cw_length_with_rsvd= FALSE; + + +static +int pw_cell_size(const pwatm_mode_t mode, const pwatm_submode_t submode) { - proto_tree *pw_atm_tree = NULL; - proto_item *ti = NULL; - tvbuff_t *next_tvb = NULL; - guint16 sequence_number = 0; - guint8 flags = 0; - guint8 length = 0; - guint16 ncells = 0; - guint16 remains = 0; - guint16 i = 0; - - if (tvb_reported_length_remaining(tvb, 0) < 4) { - if (tree) - proto_tree_add_text(tree, tvb, 0, -1, - "Error processing Message"); - return; - } - - if (tree) { - ti = proto_tree_add_boolean(tree, hf_pw_atm_n2o_cw, - tvb, 0, 0, TRUE); - PROTO_ITEM_SET_HIDDEN(ti); - ti = proto_tree_add_item(tree, proto_pw_atm_n2o_cw, - tvb, 0, 4, FALSE); - pw_atm_tree = proto_item_add_subtree(ti, ett_pw_atm); - if (pw_atm_tree == NULL) - return; - - flags = tvb_get_guint8(tvb, 0) & 0x0F; - proto_tree_add_uint_format( - pw_atm_tree, - hf_pw_atm_n2o_cw_flags, - tvb, 0, 1, flags, - "Flags: 0x%02x", - flags); - - length = tvb_get_guint8(tvb, 1) & 0x3F; - proto_tree_add_uint_format( - pw_atm_tree, - hf_pw_atm_n2o_cw_length, - tvb, 1, 1, length, - "Length: %u", - flags); - - sequence_number = tvb_get_ntohs(tvb, 2); - proto_tree_add_uint_format( - pw_atm_tree, - hf_pw_atm_n2o_cw_sequence_number, - tvb, 2, 2, sequence_number, - "Sequence Number: %u", - sequence_number); - } - - /* FF: pass info to the ATM dissector, see packet_info.h for details */ - pinfo->pw_atm_encap_type = 1; - - /* - * FF: RFC 4717: "The number of cells encapsulated in a particular - * frame can be inferred by the frame length" but "if the control - * word is used, then the flag and length bits in the control word - * are not used [and must be set to 0]" so... no reported_length in - * tvb_new_subset(). - */ - ncells = tvb_length_remaining(tvb, 4) / 52; - pinfo->pw_atm_ncells = ncells; - remains = tvb_length_remaining(tvb, 4) % 52; - - for (i = 0; i < ncells; i++) { - next_tvb = tvb_new_subset(tvb, - 4 + (i * 52), - 52, - -1); - call_dissector(atm_h, next_tvb, pinfo, tree); - } - - /* - * FF: RFC 4717 "if the pseudowire traverses a network link that - * requires a minimum frame size, with a minimum frame size of 64 - * octets, then such links will apply padding to the pseudowire PDU - * to reach its minimum frame size" or this is a malformed PDU, - * anyway... - */ - if (remains) { - next_tvb = tvb_new_subset(tvb, - 4 + (i * 52), - remains, - -1); - call_dissector(data_h, next_tvb, pinfo, tree); - } + switch(mode) + { + case PWATM_MODE_N1_NOCW: + case PWATM_MODE_N1_CW: + return SIZEOF_N1_PW_CELL; + case PWATM_MODE_11_VCC: + return SIZEOF_11_VCC_PW_CELL; + case PWATM_MODE_11_VPC: + return SIZEOF_11_VPC_PW_CELL; + case PWATM_MODE_AAL5_PDU: + /* AAL5 PDU size is n*48 bytes */ + return SIZEOF_ATM_CELL_PAYLOAD; + case PWATM_MODE_AAL5_SDU: + if (PWATM_SUBMODE_ADMIN_CELL == submode) + { + return SIZEOF_N1_PW_CELL; /*n:1 encapsulation is used for admin cells*/ + } + else + { + DISSECTOR_ASSERT_NOT_REACHED(); + return 0; + } + default: + DISSECTOR_ASSERT_NOT_REACHED(); + return 0; + } } -static void -dissect_pw_atm_n2o_nocw(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +static +int pw_cell_header_size(const pwatm_mode_t mode, const pwatm_submode_t submode) { - proto_item *ti = NULL; - tvbuff_t *next_tvb = NULL; - guint16 ncells = 0; - guint16 remains = 0; - guint16 i = 0; - - /* - * FF: all comments in dissect_pw_atm_n2o_cw() apply here - * as well, thus not repeated. - */ - - if (tvb_reported_length_remaining(tvb, 0) < 52) { - if (tree) - proto_tree_add_text(tree, tvb, 0, -1, - "Error processing Message"); - return; - } - - if (tree) { - ti = proto_tree_add_boolean(tree, hf_pw_atm_n2o_nocw, - tvb, 0, 0, TRUE); - PROTO_ITEM_SET_HIDDEN(ti); - } - - pinfo->pw_atm_encap_type = 1; - ncells = tvb_length_remaining(tvb, 0) / 52; - pinfo->pw_atm_ncells = ncells; - remains = tvb_length_remaining(tvb, 0) % 52; - - for (i = 0; i < ncells; i++) { - next_tvb = tvb_new_subset(tvb, - (i * 52), - 52, - -1); - call_dissector(atm_h, next_tvb, pinfo, tree); - } - - if (remains) { - next_tvb = tvb_new_subset(tvb, - (i * 52), - remains, - -1); - call_dissector(data_h, next_tvb, pinfo, tree); - } + switch(mode) + { + case PWATM_MODE_N1_NOCW: + case PWATM_MODE_N1_CW: + return SIZEOF_N1_PW_CELL_HEADER; + case PWATM_MODE_11_VCC: + return SIZEOF_11_VCC_PW_CELL_HEADER; + case PWATM_MODE_11_VPC: + return SIZEOF_11_VPC_PW_CELL_HEADER; + case PWATM_MODE_AAL5_SDU: + if (PWATM_SUBMODE_ADMIN_CELL == submode) + { + return SIZEOF_N1_PW_CELL_HEADER; /*n:1 encapsulation is used for admin cells*/ + } + else + { + DISSECTOR_ASSERT_NOT_REACHED(); + return 0; + } + case PWATM_MODE_AAL5_PDU: /*not applicable*/ + default: + DISSECTOR_ASSERT_NOT_REACHED(); + return 0; + } } -#if 0 -static void -dissect_pw_atm_o2o_cw(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +static +int number_of_cells(const pwatm_mode_t mode + ,const pwatm_submode_t submode + ,const gint payload_size + ,gint* const remainder_size) { - (void)tvb; - (void)pinfo; - (void)tree; + int cells; + assert(payload_size >= 0); + assert(remainder_size != NULL); + + switch(mode) + { + case PWATM_MODE_N1_NOCW: + case PWATM_MODE_N1_CW: + case PWATM_MODE_11_VCC: + case PWATM_MODE_11_VPC: + case PWATM_MODE_AAL5_PDU: + cells = payload_size / pw_cell_size(mode,submode); + *remainder_size = payload_size - (cells * pw_cell_size(mode,submode)); + return cells; + case PWATM_MODE_AAL5_SDU: + if (PWATM_SUBMODE_ADMIN_CELL == submode) + { + cells = payload_size / pw_cell_size(mode,submode); + if (cells > 1) cells = 1; /*max. 1 admin cell may be present in aal5 sdu mode */ + *remainder_size = payload_size - (cells * pw_cell_size(mode,submode)); + return cells; + } + else + { + /*not applicable*/ + } + /*fallthrough*/ + default: + DISSECTOR_ASSERT_NOT_REACHED(); + *remainder_size = payload_size; + return 0; + } + } -static void -dissect_pw_atm_o2o_nocw(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) + +static +void col_append_pw_info(packet_info * pinfo + ,const int payload_size + ,const int cells + ,const int padding_size) { - (void)tvb; - (void)pinfo; - (void)tree; + pwatm_private_data_t* pd; + assert(pinfo != NULL); + + pd = pinfo->private_data; + assert(pd != NULL); + + if (pd->props & PWC_ANYOF_CW_BAD) + { + col_append_str(pinfo->cinfo, COL_INFO, "CW:Bad"); + } + + if (pd->props & PWC_PAY_SIZE_BAD) + { + if (pd->props & PWC_ANYOF_CW_BAD) + { + col_append_str(pinfo->cinfo, COL_INFO, ", "); + } + col_append_str(pinfo->cinfo, COL_INFO, "Payload size:Bad, "); + col_append_fstr(pinfo->cinfo, COL_INFO, "%d byte%s" + ,(int)payload_size + ,plurality(payload_size,"","s")); + } + + if (pd->props == 0) /*omit "atm cells" etc if something is wrong*/ + { + /* number of cells may be not known */ + if (cells >=0) + col_append_fstr(pinfo->cinfo, COL_INFO, "%d ATM cell%s" + ,cells + ,plurality(cells,"","s")); + /* + * Display ATM-specific attributes which are the same + * across all the cells in the pw packet. + * Meanings of values: + * (-1) unknown - not displayed, + * (-2) "not the same in all cells" - not displayed + * positive values - ok, displayed + */ + if (pd->cumulative.vpi >= 0) + col_append_fstr(pinfo->cinfo, COL_INFO, ", VPI:%.4d", pd->cumulative.vpi); + if (pd->cumulative.vci >= 0) + col_append_fstr(pinfo->cinfo, COL_INFO, ", VCI:%.5d", pd->cumulative.vci); + if (pd->cumulative.pti >= 0) + col_append_fstr(pinfo->cinfo, COL_INFO, ", PTI:%.1d", pd->cumulative.pti); + if (pd->cumulative.clp >= 0) + col_append_fstr(pinfo->cinfo, COL_INFO, ", CLP:%.1d", pd->cumulative.clp); + } + + if (padding_size != 0) + { + col_append_fstr(pinfo->cinfo, COL_INFO, ", %d padding" + ,(int)padding_size); + } } + +static +void prepare_pseudo_header_atm( + union wtap_pseudo_header * const ph, + const pwatm_private_data_t * const pdata, + const unsigned aal) +{ + assert(NULL != pdata); + assert(NULL != ph); + + memset(ph,0,sizeof(*ph)); /* it is OK to clear unknown values */ + ph->atm.flags = 0; /* status flags */ + ph->atm.aal = aal; + ph->atm.type = TRAF_UNKNOWN; + ph->atm.subtype = TRAF_ST_UNKNOWN; + ph->atm.vpi = (pdata->vpi >= 0) ? pdata->vpi : 0 /*unknown*/; + ph->atm.vci = (pdata->vci >= 0) ? pdata->vci : 0 /*unknown*/; + ph->atm.aal2_cid = 0; /*not applicable*//* channel id */ + ph->atm.channel = 0; /*unknown*//* link: 0 for DTE->DCE, 1 for DCE->DTE */ + ph->atm.cells = 0; /*zero indicates that we do not have trailer info*/ + /*user-to-user indicator & CPI*/ + ph->atm.aal5t_u2u = 0; /* all bits unknown except lsb of UU */ + if (pdata->aal5_sdu_frame_relay_cr_bit) + { /* Let's give Frame Relay C/R bit to ATM dissector.*/ + ph->atm.aal5t_u2u |= (1<<8); /*UU octet is at << 8 in aal5t_u2u*/ + } + ph->atm.aal5t_len = 0; /*unknown*//* length of the packet from trailer*/ + ph->atm.aal5t_chksum = 0; /*unknown*//* checksum for AAL5 packet from trailer */ + return; +} -static void -dissect_pw_atm_aal5_pdu_cw(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) + +static +void dissect_payload_and_padding( + tvbuff_t * tvb + ,packet_info * pinfo + ,proto_tree * tree + ,const gint payload_size + ,const gint padding_size) { - (void)tvb; - (void)pinfo; - (void)tree; + int dissected; + tvbuff_t* tvb_2; + pwatm_private_data_t* pd; + + assert(NULL != pinfo); + pd = pinfo->private_data; + assert(NULL != pd); + + for(dissected = 0, pd->pw_cell_number = 0; + payload_size > dissected; + ++(pd->pw_cell_number)) + { + tvb_2 = tvb_new_subset(tvb,dissected,-1,-1); + dissected += call_dissector(dh_cell_header, tvb_2, pinfo, tree); + + tvb_2 = tvb_new_subset(tvb,dissected,-1,-1); + + /*dissect as oam for specific vci/pti, just like atm dissector does*/ + if (pd->vci >= 0 && pd->pti >=0) + { + if (atm_is_oam_cell(pd->vci,pd->pti)) + { + pd->cell_mode_oam = TRUE; + } + } + + if (pd->cell_mode_oam) + { + union wtap_pseudo_header* pseudo_header_save; + union wtap_pseudo_header ph; + tvbuff_t* tvb_3; + int bytes_to_dissect; + /* prepare buffer for old-style dissector */ + /* oam cell is always 48 bytes, but payload_size maybe too small */ + if ((payload_size - dissected) >= SIZEOF_ATM_CELL_PAYLOAD) + bytes_to_dissect = SIZEOF_ATM_CELL_PAYLOAD; + else + bytes_to_dissect = (payload_size - dissected); + tvb_3 = tvb_new_subset(tvb_2,0,bytes_to_dissect,-1); + /*aal5_sdu: disable filling columns after 1st (valid) oam cell*/ + if (pd->mode == PWATM_MODE_AAL5_SDU && pd->pw_cell_number > 0) + { + pd->enable_fill_columns_by_atm_dissector = FALSE; + } + /* save & prepare new pseudo header for atm aal5 decoding */ + pseudo_header_save = pinfo->pseudo_header; + pinfo->pseudo_header = &ph; + prepare_pseudo_header_atm(&ph,pd,AAL_OAMCELL); + + call_dissector(dh_atm_oam_cell, tvb_3, pinfo, tree); + dissected += bytes_to_dissect; + /* restore pseudo header */ + pinfo->pseudo_header = pseudo_header_save; + } + else + { + dissected += call_dissector(dh_cell, tvb_2, pinfo, tree); + } + } + + if (padding_size != 0) + { + tvbuff_t* tvb_2; + tvb_2 = tvb_new_subset(tvb + ,(tvb_reported_length_remaining(tvb, 0) - padding_size) + ,-1 + ,-1); + call_dissector(dh_padding, tvb_2, pinfo, tree); + } + return; } -static void -dissect_pw_atm_aal5_pdu_nocw(tvbuff_t *tvb, packet_info *pinfo, - proto_tree *tree) +static +gboolean too_small_packet_or_notpw(tvbuff_t * tvb + ,packet_info * pinfo + ,proto_tree * tree + ,const int proto_handler + ,const char * const proto_name_column) { - (void)tvb; - (void)pinfo; - (void)tree; + gint packet_size; + packet_size = tvb_reported_length_remaining(tvb, 0); + /* + * FIXME + * "4" below should be replaced by something like "min_packet_size_this_dissector" + * Also call to dissect_try_cw_first_nibble() should be moved before this block + */ + if (packet_size < 4) /* 4 is smallest size which may be sensible (for PWACH dissector) */ + { + if (tree) + { + proto_item *item; + item = proto_tree_add_item(tree, proto_handler, tvb, 0, -1, FALSE); + expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR, + "PW packet size (%d) is too small to carry sensible information" + ,(int)packet_size); + } + /* represent problems in the Packet List pane */ + if (check_col(pinfo->cinfo, COL_PROTOCOL)) + { + col_set_str(pinfo->cinfo, COL_PROTOCOL, proto_name_column); + } + if (check_col(pinfo->cinfo, COL_INFO)) + { + col_set_str(pinfo->cinfo, COL_INFO, + "Malformed: PW packet is too small"); + } + return TRUE; + } + if (dissect_try_cw_first_nibble(tvb, pinfo, tree)) + { + return TRUE; + } + return FALSE; } -static void -dissect_pw_atm_aal5_sdu_cw(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) + +/* + * NOTE. RFC describes ATM-specific byte in a cumbersome way. + * It is a part of CW, but at the same time, it must be repeated + * with each cell, _except_ first. + * + * Alternatively, ATM-specific byte may be considered as part of + * PW payload (i.e., as part of pw atm cell header), so we can say that + * it is being repeated with each cell. + * + * This dissector is written according to the latter consideration. + */ +static +void dissect_11_or_aal5_pdu(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree) { - (void)tvb; - (void)pinfo; - (void)tree; + const char *proto_name_column; + const char *proto_name_tree = NULL; + gint payload_size; + int cells; + pwatm_private_data_t pd = PWATM_PRIVATE_DATA_T_INITIALIZER; + void * pd_save = pinfo->private_data; + pinfo->private_data = &pd; + + proto_name_column = &shortname_11_or_aal5_pdu[0]; + if (too_small_packet_or_notpw(tvb,pinfo,tree,proto_11_or_aal5_pdu,proto_name_column)) + { + return; + } + pd.packet_size = tvb_reported_length_remaining(tvb, 0); + + /* + * Guess encapsulation mode according to M & V bits from the 3rd byte of CW. + * Also adjust protocol name strings. + */ + { + guint8 third_byte; + third_byte = tvb_get_guint8(tvb, 3); + if (0 == (third_byte & 0x80 /*generic_cw.m*/)) + { /*1:1 modes*/ + if (0 != (third_byte & 0x40 /*generic_cw.v*/)) + { + pd.mode = PWATM_MODE_11_VPC; + proto_name_column = &shortname_11_vpc[0]; + proto_name_tree = &longname_pw_atm_11_vpc[0]; + } + else + { + pd.mode = PWATM_MODE_11_VCC; + proto_name_column = &shortname_11_vcc[0]; + proto_name_tree = &longname_pw_atm_11_vcc[0]; + } + } + else + { + pd.mode = PWATM_MODE_AAL5_PDU; + proto_name_column = &shortname_aal5_pdu[0]; + proto_name_tree = &longname_pw_atm_aal5_pdu[0]; + } + } + + + /* check how "good" is this packet */ + pd.props = PWC_PACKET_PROPERTIES_T_INITIALIZER; + if (0 != (tvb_get_guint8(tvb, 0) & 0xf0 /*bits03*/)) + { + pd.props |= PWC_CW_BAD_BITS03; + } + if (0 != (tvb_get_guint8(tvb, 0) & 0x0f /*generic_cw.rsvd*/)) + { + pd.props |= PWC_CW_BAD_RSV; + } + + /* + * Do not dissect and validate atm-specific byte (3rd byte of CW). + * It will be dissected/validated as pw cell header. + */ + + /* + * Decide about payload length and padding. + * + * Is padding allowed? + * eth header length == 14 + * mpls label length == 4 + * cw length == 4 + * min payload length == 48 + * => 14 + 4 + 4 + 48 == 70 + * => 70 >= 64 + * => no padding allowed + */ + if (MODE_11(pd.mode)) + { + gint bad_padding_size; + payload_size = pd.packet_size - (PWC_SIZEOF_CW-1); + cells = number_of_cells(pd.mode,pd.submode,payload_size,&bad_padding_size); + if (0 == cells || 0 != bad_padding_size) + { + pd.props |= PWC_PAY_SIZE_BAD; + } + } + else + { /*aal5_pdu mode*/ + gint bad_padding_size; + payload_size = pd.packet_size - PWC_SIZEOF_CW; + cells = number_of_cells(pd.mode,pd.submode,payload_size,&bad_padding_size); + /* at least 1 cell must be present in the packet in this mode*/ + if (1 > cells || 0 != bad_padding_size) + { + pd.props |= PWC_PAY_SIZE_BAD; + } + cells = -1; /*this value not needed anymore, suppress pinting of it*/ + } + + if (PWATM_MODE_AAL5_PDU == pd.mode) + { + /* sub-dissectors _may_ overwrite columns in aal5_pdu mode */ + if (check_col(pinfo->cinfo, COL_PROTOCOL)) + { + col_set_str(pinfo->cinfo, COL_PROTOCOL, proto_name_column); + } + if (check_col(pinfo->cinfo, COL_INFO)) + { + col_clear(pinfo->cinfo, COL_INFO); + col_append_pw_info(pinfo, payload_size, cells, 0); + } + } + + if (tree) + { + proto_item* item; + item = proto_tree_add_item(tree, proto_11_or_aal5_pdu, tvb, 0, -1, FALSE); + /*overwrite heading line*/ + proto_item_set_text(item, proto_name_tree, 0/*-warn gcc 3.4.4*/); + pwc_item_append_text_n_items(item,cells,"good ATM cell"); + { + proto_tree* tree; + tree = proto_item_add_subtree(item, ett_encaps); + { + proto_item* item; + item = proto_tree_add_boolean(tree + ,VALUE_SELECTOR_VPC_VCC_PDU(pd.mode + ,hf_pw_type_11_vpc + ,hf_pw_type_11_vcc + ,hf_pw_type_aal5_pdu) + ,tvb, 0, 0, TRUE); + PROTO_ITEM_SET_GENERATED(item); + if (MODE_11(pd.mode)) + { + item = proto_tree_add_int(tree, hf_11_ncells, tvb, 0, 0, cells); + PROTO_ITEM_SET_GENERATED(item); + } + } + } + if (pd.props & PWC_PAY_SIZE_BAD) + { + expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR + ,"PW payload size (%d) must be <> 0 and multiple of %d" + ,(int)payload_size,pw_cell_size(pd.mode,pd.submode)); + if (payload_size != 0 && MODE_11(pd.mode)) + { + expert_add_info_format(pinfo, item, PI_MALFORMED, PI_NOTE, + "PW ATM cell [%.3d] is broken",(int)cells); + } + } + } + + { + tvbuff_t* tvb_2; + tvb_2 = tvb_new_subset(tvb, 0, PWC_SIZEOF_CW, PWC_SIZEOF_CW); + call_dissector(dh_control_word, tvb_2, pinfo, tree); + + tvb_2 = tvb_new_subset(tvb, (PWC_SIZEOF_CW-1), -1, -1); + if (MODE_11(pd.mode)) + { + dissect_payload_and_padding(tvb_2,pinfo,tree,payload_size,0); + } + else + { /*aal5_pdu mode*/ + if (payload_size != 0) + { + tvbuff_t* tvb_3; + union wtap_pseudo_header* pseudo_header_save; + union wtap_pseudo_header ph; + + tvb_3 = tvb_new_subset(tvb_2, 1, -1, -1); + /* prepare pseudo header for atm aal5 decoding */ + pseudo_header_save = pinfo->pseudo_header; + pinfo->pseudo_header = &ph; + prepare_pseudo_header_atm(&ph,&pd,AAL_5); + call_dissector(dh_atm_untruncated, tvb_3, pinfo, tree); + /* restore pseudo header */ + pinfo->pseudo_header = pseudo_header_save; + } + } + } + + if (MODE_11(pd.mode)) + { + /* overwrite everything written by sub-dissectors in 1:1 modes*/ + if (check_col(pinfo->cinfo, COL_PROTOCOL)) + { + col_set_str(pinfo->cinfo, COL_PROTOCOL, proto_name_column); + } + if (check_col(pinfo->cinfo, COL_INFO)) + { + col_clear(pinfo->cinfo, COL_INFO); + col_append_pw_info(pinfo, payload_size, cells, 0); + } + } + + pinfo->private_data = pd_save; + return; } -static void -dissect_pw_atm_aal5_sdu_nocw(tvbuff_t *tvb, packet_info *pinfo, - proto_tree *tree) + +static +void dissect_aal5_sdu(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree) { - (void)tvb; - (void)pinfo; - (void)tree; + const char *proto_name_column; + gint payload_size; + gint padding_size; + int cells; + pwatm_private_data_t pd = PWATM_PRIVATE_DATA_T_INITIALIZER; + void * pd_save = pinfo->private_data; + + pinfo->private_data = &pd; + pd.mode = PWATM_MODE_AAL5_SDU; + + proto_name_column = &shortname_aal5_sdu[0]; + if (too_small_packet_or_notpw(tvb,pinfo,tree,proto_aal5_sdu,proto_name_column)) + { + return; + } + pd.packet_size = tvb_reported_length_remaining(tvb, 0); + + /* check how "good" is this packet */ + /* also decide payload length from packet size and CW */ + if (0 != (tvb_get_guint8(tvb, 0) & 0xf0 /*bits03*/)) + { + pd.props |= PWC_CW_BAD_BITS03; + } + + pd.submode = PWATM_SUBMODE_DEFAULT; + if (0 != (tvb_get_guint8(tvb, 0) & 0x08 /*preferred_cw.T*/)) + { + pd.submode = PWATM_SUBMODE_ADMIN_CELL; + } + + if (! pref_aal5_sdu_extend_cw_length_with_rsvd) + { + if (0 != (tvb_get_guint8(tvb, 1) & 0xc0 /*preferred_cw.rsvd*/)) + { + pd.props |= PWC_CW_BAD_RSV; + } + } + { + /* RFC4717: + * [ If the packet's length (defined as the length of the layer 2 payload + * plus the length of the control word) is less than 64 bytes, the + * length field MUST be set to the packet's length. Otherwise, the + * length field MUST be set to zero... Note that the length field + * is not used in the N-to-one mode and MUST be set to 0. ] + * + * Also we allow some "extensions"conducted by pref_xxx. + */ + gint payload_size_from_packet; + int cw_len; /*length field from cw*/ + + payload_size_from_packet = pd.packet_size - PWC_SIZEOF_CW; + if (pref_aal5_sdu_extend_cw_length_with_rsvd) + { + cw_len = tvb_get_guint8(tvb, 1) & 0xff; + } + else + { + cw_len = tvb_get_guint8(tvb, 1) & 0x3f; + } + + /* + * Initial assumptions: no padding, + * payload size derived from psn packet size. + */ + payload_size = payload_size_from_packet; + padding_size = 0; + + if (0 == cw_len) + { + /*keep initial assumptions*/ + } + else if (!pref_aal5_sdu_allow_cw_length_nonzero + && PWATM_SUBMODE_ADMIN_CELL == pd.submode) + { + /* + * The "allow CW.Length != 0" option affects + * ATM admin cell submode only, because this submode + * is equal to N:1 encapsulation. + * CW.Length !=0 is always OK for normal (AAL5 payload) submode. + */ + pd.props |= PWC_CW_BAD_LEN_MUST_BE_0; + } + else + { + gint payload_size_from_cw; + payload_size_from_cw = cw_len - PWC_SIZEOF_CW; + if (payload_size_from_cw <= 0) + { + pd.props |= PWC_CW_BAD_PAYLEN_LE_0; + } + else if (payload_size_from_cw > payload_size_from_packet) + { + pd.props |= PWC_CW_BAD_PAYLEN_GT_PACKET; + } + else + { + + payload_size = payload_size_from_cw; + padding_size = payload_size_from_packet - payload_size_from_cw; /* >=0 */ + if (padding_size != 0) + { + /* + * Padding is not allowed in ATM admin cell submode only, + * because this submode is equal to N:1 encapsulation. + * Padding is OK for normal (AAL5 payload) submode. + */ + if (PWATM_SUBMODE_ADMIN_CELL == pd.submode) + { + pd.props |= PWC_CW_BAD_PADDING_NE_0; + /*restore sizes*/ + payload_size = payload_size_from_packet; + padding_size = 0; + } + } + } + } + + if (PWATM_SUBMODE_ADMIN_CELL == pd.submode) + { + gint bad_padding_size; + cells = number_of_cells(pd.mode,pd.submode,payload_size,&bad_padding_size); + /* only one atm admin cell is allowed in the packet in this mode*/ + if (1 != cells || 0 != bad_padding_size) + { + pd.props |= PWC_PAY_SIZE_BAD; + } + } + else + { + cells = -1; /*unknown*/ + /* Any size is allowed for AAL5 SDU payload */ + } + } + + /* fill columns in Packet List */ + if (check_col(pinfo->cinfo, COL_PROTOCOL)) + { + col_set_str(pinfo->cinfo, COL_PROTOCOL, proto_name_column); + if (PWATM_SUBMODE_ADMIN_CELL == pd.submode) + { + col_append_str(pinfo->cinfo, COL_PROTOCOL, ", OAM cell"); + } + } + + if (check_col(pinfo->cinfo, COL_INFO)) + { + col_clear(pinfo->cinfo, COL_INFO); + col_append_pw_info(pinfo, payload_size, cells, padding_size); + } + + if (tree) + { + proto_item* item; + item = proto_tree_add_item(tree, proto_aal5_sdu, tvb, 0, -1, FALSE); + { + proto_tree* tree; + tree = proto_item_add_subtree(item, ett_encaps); + { + item = proto_tree_add_boolean(tree, hf_pw_type_aal5_sdu, tvb, 0, 0, TRUE); + PROTO_ITEM_SET_GENERATED(item); + } + } + if (pd.props & PWC_PAY_SIZE_BAD) + { + DISSECTOR_ASSERT(PWATM_SUBMODE_ADMIN_CELL == pd.submode); + expert_add_info_format(pinfo, item, PI_MALFORMED ,PI_ERROR + ,"In ATM admin cell mode," + " PW payload size (%d) must be == %d (exactly 1 admin cell)" + ,(int)payload_size,(int)SIZEOF_N1_PW_CELL); + } + } + + { + tvbuff_t* tvb_2; + tvb_2 = tvb_new_subset(tvb, 0, PWC_SIZEOF_CW, PWC_SIZEOF_CW); + call_dissector(dh_control_word, tvb_2, pinfo, tree); + + tvb_2 = tvb_new_subset(tvb, PWC_SIZEOF_CW, -1, -1); + if (PWATM_SUBMODE_ADMIN_CELL == pd.submode) + { + dissect_payload_and_padding(tvb_2,pinfo,tree,payload_size,padding_size); + } + else /*AAL5 payload*/ + { + if (payload_size != 0) + { + tvbuff_t* tvb_3; + union wtap_pseudo_header* pseudo_header_save; + union wtap_pseudo_header ph; + + tvb_3 = tvb_new_subset(tvb_2, 0, payload_size, payload_size); + /* prepare pseudo header for atm aal5 decoding */ + pseudo_header_save = pinfo->pseudo_header; + pinfo->pseudo_header = &ph; + prepare_pseudo_header_atm(&ph,&pd,AAL_5); + call_dissector(dh_atm_truncated, tvb_3, pinfo, tree); /* no PAD and trailer */ + /* restore pseudo header */ + pinfo->pseudo_header = pseudo_header_save; + } + if (padding_size != 0) + { + tvbuff_t* tvb_3; + tvb_3 = tvb_new_subset(tvb_2, payload_size, padding_size, -1); + call_dissector(dh_padding, tvb_3, pinfo, tree); + } + } + } + + pinfo->private_data = pd_save; + return; } -#endif -void -proto_register_pw_atm(void) + +static +void dissect_n1_cw(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree) { - static hf_register_info hf[] = { - /* FF: general */ - { - &hf_pw_atm_n2o_cw, - { - "ATM PW, N-to-one Cell Mode (with CW)", - "pw_atm_n2o_cw", FT_BOOLEAN, - BASE_NONE, NULL, 0x0, NULL, HFILL - } - }, - { - &hf_pw_atm_n2o_nocw, - { - "ATM PW, N-to-one Cell Mode (no CW)", - "pw_atm_n2o_nocw", FT_BOOLEAN, - BASE_NONE, NULL, 0x0, NULL, HFILL - } - }, -#if 0 - { - &hf_pw_atm_o2o_cw, - { - "ATM PW, One-to-one Cell Mode (with CW)", - "pw_atm_o2o_cw", FT_BOOLEAN, - 0, NULL, 0x0, NULL, HFILL - } - }, - { - &hf_pw_atm_o2o_nocw, - { - "ATM PW, One-to-one Cell Mode (no CW)", - "pw_atm_o2o_nocw", FT_BOOLEAN, - 0, NULL, 0x0, NULL, HFILL - } - }, - { - &hf_pw_atm_aal5_pdu_cw, - { - "ATM PW, AAL5 PDU Frame Mode (with CW)", - "pw_atm_aal5_pdu_cw", FT_BOOLEAN, - 0, NULL, 0x0, NULL, HFILL - } - }, - { - &hf_pw_atm_aal5_pdu_nocw, - { - "ATM PW, AAL5 PDU Frame Mode (no CW)", - "pw_atm_aal5_pdu_nocw", FT_BOOLEAN, - 0, NULL, 0x0, NULL, HFILL - } - }, - { - &hf_pw_atm_aal5_sdu_cw, - { - "ATM PW, AAL5 SDU Frame Mode (with CW)", - "pw_atm_aal5_sdu_cw", FT_BOOLEAN, - 0, NULL, 0x0, NULL, HFILL - } - }, - { - &hf_pw_atm_aal5_sdu_nocw, - { - "ATM PW, AAL5 SDU Frame Mode (no CW)", - "pw_atm_aal5_sdu_nocw", FT_BOOLEAN, - 0, NULL, 0x0, NULL, HFILL - } - }, - /* FF: ATM One-to-one Cell Mode Control Word fields */ - { - &hf_pw_atm_o2o_cw_sequence_number, - { - "ATM One-to-one Cell Mode sequence number", - "pw_atm_o2o_cw_sequence_number", FT_UINT16, - BASE_DEC, NULL, 0x0, NULL, HFILL - } - }, - { - &hf_pw_atm_o2o_cw_flags, - { - "ATM One-to-one Cell Mode flags", - "pw_atm_o2o_cw_flags", FT_UINT8, - BASE_HEX, NULL, 0x0, NULL, HFILL - } - - }, - { - &hf_pw_atm_o2o_cw_flags_m, - { - "M (transport mode) bit", - "pw_atm_o2o_cw_flags_m", FT_BOOLEAN, - 8, TFS(&flags_set_truth), PW_ATM_O2O_CW_M, - NULL, HFILL - } - }, - { - &hf_pw_atm_o2o_cw_flags_v, - { - "V (VCI present) bit", - "pw_atm_o2o_cw_flags_v", FT_BOOLEAN, - 8, TFS(&flags_set_truth), PW_ATM_O2O_CW_V, - NULL, HFILL - } - }, - { - &hf_pw_atm_o2o_cw_flags_res, - { - "Reserved bits", - "pw_atm_o2o_cw_flags_res", FT_BOOLEAN, - 8, TFS(&flags_set_truth), PW_ATM_O2O_CW_RES, - NULL, HFILL - } - }, - { - &hf_pw_atm_o2o_cw_flags_pti, - { - "PTI bits", - "pw_atm_o2o_cw_flags_pti", FT_BOOLEAN, - 8, TFS(&flags_set_truth), PW_ATM_O2O_CW_PTI, - NULL, HFILL - } - }, - { - &hf_pw_atm_o2o_cw_flags_c, - { - "C (CLP) bit", - "pw_atm_o2o_cw_flags_c", FT_BOOLEAN, - 8, TFS(&flags_set_truth), PW_ATM_O2O_CW_C, - NULL, HFILL - } - }, - /* FF: AAL5 PDU Frame Mode Control Word fields */ - { - &hf_pw_atm_aal5_pdu_cw_sequence_number, - { - "AAL5 PDU Frame Mode sequence number", - "pw_atm_aal5_pdu_cw_sequence_number", - FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL - } - }, - /* FF: AAL5 SDU Frame Mode Control Word fields */ - { - &hf_pw_atm_aal5_sdu_cw_sequence_number, - { - "AAL5 SDU Frame Mode sequence number", - "pw_atm_aal5_sdu_cw_sequence_number", - FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL - } - }, -#endif - /* FF: ATM N-to-one Cell Mode Control Word fields */ - { - &hf_pw_atm_n2o_cw_flags, - { - "ATM N-to-one Cell Mode flags", - "pw_atm_n2o_cw_flags", FT_UINT8, - BASE_HEX, NULL, 0x0, NULL, HFILL - } - - }, - { - &hf_pw_atm_n2o_cw_length, - { - "ATM N-to-one Cell Mode flags", - "pw_atm_n2o_cw_length", FT_UINT8, - BASE_HEX, NULL, 0x0, NULL, HFILL - } - - }, - { - &hf_pw_atm_n2o_cw_sequence_number, - { - "ATM N-to-one Cell Mode sequence number", - "pw_atm_n2o_cw_sequence_number", FT_UINT16, - BASE_DEC, NULL, 0x0, NULL, HFILL - } - }, - }; - - static gint *ett[] = { - &ett_pw_atm - }; - - proto_pw_atm_n2o_cw = - proto_register_protocol("ATM PW, N-to-one Cell Mode Control Word", - "ATM PW, N-to-one Cell Mode (with CW)", - "pw_atm_n2o_cw"); - proto_pw_atm_n2o_nocw = - proto_register_protocol("ATM PW, N-to-one Cell Mode (no CW)", - "ATM PW, N-to-one Cell Mode (no CW)", - "pw_atm_n2o_nocw"); -#if 0 - proto_pw_atm_o2o_cw = - proto_register_protocol("ATM PW, One-to-one Cell Mode Control Word", - "ATM PW, One-to-one Cell Mode (with CW)", - "pw_atm_o2o_cw"); - proto_pw_atm_o2o_nocw = - proto_register_protocol("ATM PW, One-to-one Cell Mode (no CW)", - "ATM PW, One-to-one Cell Mode (no CW)", - "pw_atm_o2o_nocw"); - proto_pw_atm_aal5_pdu_cw = - proto_register_protocol("ATM PW, AAL5 PDU Frame Mode Control Word", - "ATM PW, AAL5 PDU Frame Mode (with CW)", - "pw_atm_aal5_pdu_cw"); - proto_pw_atm_aal5_pdu_nocw = - proto_register_protocol("ATM PW, AAL5 PDU Frame Mode (no CW)", - "ATM PW, AAL5 PDU Frame Mode (no CW)", - "pw_atm_aal5_pdu_nocw"); - proto_pw_atm_aal5_sdu_cw = - proto_register_protocol("ATM PW, AAL5 SDU Frame Mode Control Word", - "ATM PW, AAL5 SDU Frame Mode (with CW)", - "pw_atm_aal5_sdu_cw"); - proto_pw_atm_aal5_sdu_nocw = - proto_register_protocol("ATM PW, AAL5 SDU Frame Mode (no CW)", - "ATM PW, AAL5 SDU Frame Mode (no CW)", - "pw_atm_aal5_sdu_nocw"); -#endif + const char *proto_name_column; + gint payload_size; + gint padding_size; + int cells; + pwatm_private_data_t pd = PWATM_PRIVATE_DATA_T_INITIALIZER; + void * pd_save = pinfo->private_data; - proto_register_field_array(proto_pw_atm_n2o_cw, hf, array_length(hf)); - proto_register_subtree_array(ett, array_length(ett)); - - register_dissector("pw_atm_n2o_cw", - dissect_pw_atm_n2o_cw, - proto_pw_atm_n2o_cw); - register_dissector("pw_atm_n2o_nocw", - dissect_pw_atm_n2o_nocw, - proto_pw_atm_n2o_nocw); -#if 0 - register_dissector("pw_atm_o2o_cw", - dissect_pw_atm_o2o_cw, - proto_pw_atm_o2o_cw); - register_dissector("pw_atm_o2o_nocw", - dissect_pw_atm_o2o_nocw, - proto_pw_atm_o2o_nocw); - register_dissector("pw_atm_aal5_pdu_cw", - dissect_pw_atm_aal5_pdu_cw, - proto_pw_atm_aal5_pdu_cw); - register_dissector("pw_atm_aal5_pdu_nocw", - dissect_pw_atm_aal5_pdu_nocw, - proto_pw_atm_aal5_pdu_nocw); - register_dissector("pw_atm_aal5_sdu_cw", - dissect_pw_atm_aal5_sdu_cw, - proto_pw_atm_aal5_sdu_cw); - register_dissector("pw_atm_aal5_sdu_nocw", - dissect_pw_atm_aal5_sdu_nocw, - proto_pw_atm_aal5_sdu_nocw); -#endif + pinfo->private_data = &pd; + pd.mode = PWATM_MODE_N1_CW; + + proto_name_column = &shortname_n1_cw[0]; + if (too_small_packet_or_notpw(tvb,pinfo,tree,proto_n1_cw,proto_name_column)) + { + return; + } + pd.packet_size = tvb_reported_length_remaining(tvb, 0); + + /* check how "good" is this packet */ + /* also decide payload length from packet size and CW */ + pd.props = PWC_PACKET_PROPERTIES_T_INITIALIZER; + if (0 != (tvb_get_guint8(tvb, 0) & 0xf0 /*bits03*/)) + { + pd.props |= PWC_CW_BAD_BITS03; + } + if (0 != (tvb_get_guint8(tvb, 0) & 0x0f /*preferred_cw.flags*/)) + { + pd.props |= PWC_CW_BAD_FLAGS; + } + if (! pref_n1_cw_extend_cw_length_with_rsvd) + { + if (0 != (tvb_get_guint8(tvb, 1) & 0xc0 /*preferred_cw.rsvd*/)) + { + pd.props |= PWC_CW_BAD_RSV; + } + } + { + /* RFC4717: + * [ If the packet's length (defined as the length of the layer 2 payload + * plus the length of the control word) is less than 64 bytes, the + * length field MUST be set to the packet's length. Otherwise, the + * length field MUST be set to zero... Note that the length field + * is not used in the N-to-one mode and MUST be set to 0. ] + * + * Also we allow some "extensions"conducted by pref_xxx. + */ + gint payload_size_from_packet; + int cw_len; /*length field from cw*/ + + payload_size_from_packet = pd.packet_size - PWC_SIZEOF_CW; + if (pref_n1_cw_extend_cw_length_with_rsvd) + { + cw_len = tvb_get_guint8(tvb, 1) & 0xff; + } + else + { + cw_len = tvb_get_guint8(tvb, 1) & 0x3f; + } + + /* + * Initial assumptions: no padding, + * payload size derived from psn packet size. + */ + payload_size = payload_size_from_packet; + padding_size = 0; + + if (0 == cw_len) + { + /*keep initial assumptions*/ + } + else if (!pref_n1_cw_allow_cw_length_nonzero) + { + pd.props |= PWC_CW_BAD_LEN_MUST_BE_0; + } + else + { + gint payload_size_from_cw; + payload_size_from_cw = cw_len - PWC_SIZEOF_CW; + if (payload_size_from_cw <= 0) + { + pd.props |= PWC_CW_BAD_PAYLEN_LE_0; + } + else if (payload_size_from_cw > payload_size_from_packet) + { + pd.props |= PWC_CW_BAD_PAYLEN_GT_PACKET; + } + else + { + + payload_size = payload_size_from_cw; + padding_size = payload_size_from_packet - payload_size_from_cw; /* >=0 */ + if (padding_size != 0) + { + pd.props |= PWC_CW_BAD_PADDING_NE_0; + /*restore sizes*/ + payload_size = payload_size_from_packet; + padding_size = 0; + } + } + } + { + gint bad_padding_size; + cells = number_of_cells(pd.mode,pd.submode,payload_size,&bad_padding_size); + if (0 == cells || 0 != bad_padding_size) + { + pd.props |= PWC_PAY_SIZE_BAD; + } + } + } + + if (tree) + { + proto_item* item; + item = proto_tree_add_item(tree, proto_n1_cw, tvb, 0, -1, FALSE); + pwc_item_append_text_n_items(item,cells,"good ATM cell"); + { + proto_tree* tree; + tree = proto_item_add_subtree(item, ett_encaps); + { + proto_item* item; + item = proto_tree_add_boolean(tree, hf_pw_type_n1_cw, tvb, 0, 0, TRUE); + PROTO_ITEM_SET_GENERATED(item); + item = proto_tree_add_int(tree, hf_n1_cw_ncells, tvb, 0, 0, cells); + PROTO_ITEM_SET_GENERATED(item); + } + } + if (pd.props & PWC_PAY_SIZE_BAD) + { + if (payload_size != 0) + { + expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR, + "PW ATM cell [%.3d] is broken",(int)cells); + } + expert_add_info_format(pinfo, item, PI_MALFORMED + , (payload_size == 0) ? PI_ERROR : PI_NOTE + ,"PW payload size (%d) must be <>0 and multiple of %d" + ,(int)payload_size,(int)SIZEOF_N1_PW_CELL); + } + } + + { + tvbuff_t* tvb_2; + tvb_2 = tvb_new_subset(tvb, 0, PWC_SIZEOF_CW, PWC_SIZEOF_CW); + call_dissector(dh_control_word, tvb_2, pinfo, tree); + + tvb_2 = tvb_new_subset(tvb, PWC_SIZEOF_CW, -1, -1); + dissect_payload_and_padding(tvb_2,pinfo,tree,payload_size,padding_size); + } + + /* fill columns in Packet List */ + /* overwrite everything written by sub-dissectors */ + if (check_col(pinfo->cinfo, COL_PROTOCOL)) + { + col_set_str(pinfo->cinfo, COL_PROTOCOL, proto_name_column); + } + + if (check_col(pinfo->cinfo, COL_INFO)) + { + col_clear(pinfo->cinfo, COL_INFO); + col_append_pw_info(pinfo, payload_size, cells, padding_size); + } + + pinfo->private_data = pd_save; + return; } -void -proto_reg_handoff_pw_atm(void) + +static +void dissect_n1_nocw(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree) { - dissector_handle_t pw_atm_n2o_cw_h; - dissector_handle_t pw_atm_n2o_nocw_h; -#if 0 - dissector_handle_t pw_atm_o2o_cw_h; - dissector_handle_t pw_atm_o2o_nocw_h; - dissector_handle_t pw_atm_aal5_pdu_cw_h; - dissector_handle_t pw_atm_aal5_pdu_nocw_h; - dissector_handle_t pw_atm_aal5_sdu_cw_h; - dissector_handle_t pw_atm_aal5_sdu_nocw_h; -#endif + const char *proto_name_column = &shortname_n1_nocw[0]; + gint payload_size; + int cells; + pwatm_private_data_t pd = PWATM_PRIVATE_DATA_T_INITIALIZER; + void * pd_save = pinfo->private_data; - pw_atm_n2o_cw_h = find_dissector("pw_atm_n2o_cw"); - dissector_add("mpls.label", LABEL_INVALID, pw_atm_n2o_cw_h); + pinfo->private_data = &pd; + pd.mode = PWATM_MODE_N1_NOCW; + pd.packet_size = tvb_reported_length_remaining(tvb, 0); - pw_atm_n2o_nocw_h = find_dissector("pw_atm_n2o_nocw"); - dissector_add("mpls.label", LABEL_INVALID, pw_atm_n2o_nocw_h); -#if 0 - pw_atm_o2o_cw_h = find_dissector("pw_atm_o2o_cw"); - dissector_add("mpls.label", LABEL_INVALID, pw_atm_o2o_cw_h); + /* check how "good" is this packet */ + /* also decide payload length from packet size */ + pd.props = PWC_PACKET_PROPERTIES_T_INITIALIZER; + payload_size = pd.packet_size; + { + gint bad_padding_size; + cells = number_of_cells(pd.mode,pd.submode,pd.packet_size,&bad_padding_size); + if (cells == 0 || bad_padding_size != 0) + { + pd.props |= PWC_PAY_SIZE_BAD; + } + } - pw_atm_o2o_nocw_h = find_dissector("pw_atm_o2o_nocw"); - dissector_add("mpls.label", LABEL_INVALID, pw_atm_o2o_nocw_h); + if (tree) + { + proto_item* item; + item = proto_tree_add_item(tree, proto_n1_nocw, tvb, 0, -1, FALSE); + pwc_item_append_text_n_items(item,cells,"ATM cell"); + { + proto_tree* tree; + tree = proto_item_add_subtree(item, ett_encaps); + { + proto_item* item; + item = proto_tree_add_boolean(tree, hf_pw_type_n1_nocw, tvb, 0, 0, TRUE); + PROTO_ITEM_SET_GENERATED(item); + item = proto_tree_add_int(tree, hf_n1_nocw_ncells, tvb, 0, 0, cells); + PROTO_ITEM_SET_GENERATED(item); + } + } + if (pd.props & PWC_PAY_SIZE_BAD) + { + if (payload_size != 0) + { + expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR, + "Last PW ATM cell [%.3d] is broken",(int)cells); + } + expert_add_info_format(pinfo, item, PI_MALFORMED + , (payload_size == 0) ? PI_ERROR : PI_NOTE + ,"PW payload size (%d) must be <>0 and multiple of %d" + ,(int)payload_size,(int)SIZEOF_N1_PW_CELL); + } + } + + dissect_payload_and_padding(tvb,pinfo,tree,payload_size,0); + + /* fill columns in Packet List */ + /* overwrite everything written by sub-dissectors */ + if (check_col(pinfo->cinfo, COL_PROTOCOL)) + { + col_set_str(pinfo->cinfo, COL_PROTOCOL, proto_name_column); + } - pw_atm_aal5_pdu_cw_h = find_dissector("pw_atm_aal5_pdu_cw"); - dissector_add("mpls.label", LABEL_INVALID, pw_atm_aal5_pdu_cw_h); + if (check_col(pinfo->cinfo, COL_INFO)) + { + col_clear(pinfo->cinfo, COL_INFO); + col_append_pw_info(pinfo, payload_size, cells, 0); + } - pw_atm_aal5_pdu_nocw_h = find_dissector("pw_atm_aal5_pdu_nocw"); - dissector_add("mpls.label", LABEL_INVALID, pw_atm_aal5_pdu_nocw_h); + pinfo->private_data = pd_save; + return; +} - pw_atm_aal5_sdu_cw_h = find_dissector("pw_atm_aal5_sdu_cw"); - dissector_add("mpls.label", LABEL_INVALID, pw_atm_aal5_sdu_cw_h); - pw_atm_aal5_sdu_nocw_h = find_dissector("pw_atm_aal5_sdu_nocw"); - dissector_add("mpls.label", LABEL_INVALID, pw_atm_aal5_sdu_nocw_h); -#endif +static +void proto_item_append_text_cwb3_fields(proto_item * item, const pwatm_private_data_t * const pd) +{ + if (NULL == item) return; + assert(NULL != pd); + if (pd->cwb3.m >= 0) + proto_item_append_text(item, "M:%.1u " , (unsigned)(pd->cwb3.m)); + if (pd->cwb3.v >= 0) + proto_item_append_text(item, "V:%.1u " , (unsigned)(pd->cwb3.v)); + if (pd->cwb3.rsv >= 0) + proto_item_append_text(item, "RSV:%.1u ", (unsigned)(pd->cwb3.rsv)); + if (pd->cwb3.u >= 0) + proto_item_append_text(item, "U:%.1u " , (unsigned)(pd->cwb3.u)); + if (pd->cwb3.e >= 0) + proto_item_append_text(item, "EFCI:%.1u ",(unsigned)(pd->cwb3.e)); + if (pd->cwb3.clp >= 0) + proto_item_append_text(item, "CLP:%.1u ", (unsigned)(pd->cwb3.clp)); + return; +} + + +static +void dissect_control_word(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree) +{ + pwatm_private_data_t* pd; + pd = pinfo->private_data; + assert(pd != NULL); + + /* + * NB: do not touch columns -- keep info from previous dissector + */ + + { + gint size; + size = tvb_reported_length_remaining(tvb, 0); + if (size < PWC_SIZEOF_CW) + { + if (tree) + { + proto_item *item; + item = proto_tree_add_item(tree, proto_control_word, tvb, 0, -1, FALSE); + expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR, + "Packet (size: %d) is too small to carry MPLS PW Control Word" + ,(int)size); + } + return; + } + } + + if (tree) + { + proto_item* item_top; + item_top = proto_tree_add_item(tree, proto_control_word, tvb, 0, -1, FALSE); + pwc_item_append_cw(item_top,tvb_get_ntohl(tvb, 0),FALSE); + + { + proto_tree* tree; + tree = proto_item_add_subtree(item_top, ett_cw); + { + proto_item* item; + /* bits 0..3 */ + item = proto_tree_add_item(tree, hf_cw_bits03, tvb, 0, 1, FALSE); + if (pd->props & PWC_CW_BAD_BITS03) + { + /* add item to tree (and show it) only if its value is wrong*/ + expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR + ,"Bits 0..3 of Control Word must be 0"); + } + else + { + PROTO_ITEM_SET_HIDDEN(item); /* show only in error cases */ + } + + /* flags */ + if (MODE_N1(pd->mode)) + { + item = proto_tree_add_item(tree, hf_pref_cw_flags, tvb, 0, 1, FALSE); + if (pd->props & PWC_CW_BAD_FLAGS) + { + expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR + ,"Flags must be 0 for PW ATM N:1 encapsulation"); + } + } + if (pd->mode == PWATM_MODE_AAL5_SDU) + { + item = proto_tree_add_item(tree, hf_pref_cw_a5s_t, tvb, 0, 1, FALSE); + item = proto_tree_add_item(tree, hf_pref_cw_a5s_e, tvb, 0, 1, FALSE); + item = proto_tree_add_item(tree, hf_pref_cw_a5s_c, tvb, 0, 1, FALSE); + item = proto_tree_add_item(tree, hf_pref_cw_a5s_u, tvb, 0, 1, FALSE); + /* + * rfc4717: [When FRF.8.1 Frame Relay/ATM PVC Service Interworking [RFC3916] + * traffic is being transported, the CPCS-UU Least Significant Bit + * (LSB) of the AAL5 CPCS-PDU may contain the Frame Relay C/R bit. + * The ingress router, PE1, SHOULD copy this bit to the U bit of the + * control word. The egress router, PE2, SHOULD copy the U bit to + * the CPCS-UU Least Significant Bit (LSB) of the AAL5 CPCS PDU.] + * + * Let's remember this bit (and then transfer it to ATM dissector). + */ + pd->aal5_sdu_frame_relay_cr_bit = + (0 == (tvb_get_guint8(tvb, 0) & 0x01 /*preferred_cw.U*/)) + ? FALSE : TRUE; + } + + /* reserved bits */ + if (MODE_11_OR_AAL5_PDU(pd->mode) + || (MODE_N1(pd->mode) && !pref_n1_cw_extend_cw_length_with_rsvd) + /* for N:1 add RSV only if it is NOT used in length */ + || ((pd->mode == PWATM_MODE_AAL5_SDU) && !pref_aal5_sdu_extend_cw_length_with_rsvd) + /* for AAl5 SDU add RSV only if it is NOT used in length */) + { + if (MODE_11_OR_AAL5_PDU(pd->mode)) + { + item = proto_tree_add_item(tree + ,hf_generic_cw_rsv, tvb, 0, 1, FALSE); + } + else + { /*preferred cw*/ + item = proto_tree_add_item(tree + ,hf_pref_cw_rsv, tvb, 1, 1, FALSE); + } + + if (pd->props & PWC_CW_BAD_RSV) + { + expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR + ,"Reserved bits in Control Word must be 0"); + } + else + { + PROTO_ITEM_SET_HIDDEN(item); /*...and show only in error cases */ + } + } + + /* length */ + if (MODE_N1(pd->mode) + || (PWATM_MODE_AAL5_SDU == pd->mode)) + { + { + int hf_len = hf_pref_cw_len; + if (MODE_N1(pd->mode)) + { + if (pref_n1_cw_extend_cw_length_with_rsvd) + hf_len = hf_pref_cw_rsvlen; + } + else /*PW_MODE_AAL5_SDU*/ + { + if (pref_aal5_sdu_extend_cw_length_with_rsvd) + hf_len = hf_pref_cw_rsvlen; + } + item = proto_tree_add_item(tree, hf_len, tvb, 1, 1, FALSE); + } + if (pd->props & PWC_CW_BAD_LEN_MUST_BE_0) + { + expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR + ,"Bad Length: must be 0 for this encapsulation"); + } + if (pd->props & PWC_CW_BAD_PAYLEN_LE_0) + { + expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR + ,"Bad Length: too small, must be >= %d" + ,(int)(PWC_SIZEOF_CW+SIZEOF_N1_PW_CELL)); + } + if (pd->props & PWC_CW_BAD_PAYLEN_GT_PACKET) + { + expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR + ,"Bad Length: must be <= than PSN packet size (%d)" + ,(int)pd->packet_size); + } + if (pd->props & PWC_CW_BAD_PADDING_NE_0) + { + expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR + ,"Bad Length: must be == PSN packet size (%d), no padding allowed" + ,(int)pd->packet_size); + } + } + + /* sequence number */ + (void)proto_tree_add_item(tree, hf_cw_seq, tvb + ,MODE_11_OR_AAL5_PDU(pd->mode) ? 1 : 2, 2, FALSE); + + /* atm-specific byte */ + if (MODE_11(pd->mode)) + { + (void) proto_tree_add_item(tree, hf_gen_cw_atmbyte, tvb, 3, 1, FALSE); + /* + * no need to highlight item in the tree, therefore + * expert_add_info_format() is not used here. + */ + item = proto_tree_add_text(tree,tvb,3,1 + ,"ATM-specific byte of CW is fully dissected below as %s%s" + ,(PWATM_MODE_11_VPC == pd->mode) ? "a part of " : "" + ,"PW ATM Cell Header [000]"); + PROTO_ITEM_SET_GENERATED(item); + /* + * Note: if atm-specific byte contains something wrong + * (e.g. non-zero RSV or inadequate V), CW is not + * marked as "bad". + */ + } + + /*3rd byte of CW*/ + if (PWATM_MODE_AAL5_PDU == pd->mode) + { + tvbuff_t* tvb_2; + tvb_2 = tvb_new_subset(tvb, (PWC_SIZEOF_CW-1), -1, -1); + call_dissector(dh_cell_header, tvb_2, pinfo, tree); + proto_item_append_text(item_top,", "); + proto_item_append_text_cwb3_fields(item_top,pd); + } + } + } + } + return; +} + + +/* + * This function is also used to dissect 3rd byte of CW in AAL5 PDU mode. + */ +static +int dissect_cell_header(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree) +{ + pwatm_private_data_t * pd; + gboolean is_enough_data; + int dissect_size; + + pd = pinfo->private_data; + assert (NULL != pd); + pd->vpi = pd->vci = pd->pti = -1; + pd->cwb3.clp = pd->cwb3.m = pd->cwb3.v = pd->cwb3.rsv = pd->cwb3.u = pd->cwb3.e = -1; + + if (PWATM_MODE_AAL5_PDU == pd->mode) + { + if (tvb_reported_length_remaining(tvb, 0) < 1) + { + is_enough_data = FALSE; + dissect_size = 0; + } + else + { + is_enough_data = TRUE; + dissect_size = 1; + } + } + else + { + gint size; + size = tvb_reported_length_remaining(tvb, 0); + + if (size < pw_cell_header_size(pd->mode,pd->submode)) + { + is_enough_data = FALSE; + dissect_size = size; + } + else + { + is_enough_data = TRUE; + dissect_size = pw_cell_header_size(pd->mode,pd->submode); + } + } + + /* + * NB: do not touch columns -- keep info from previous dissector + */ + + /* Collect info for upper-level dissectors regardless of + * the presence of the tree + */ + if (is_enough_data) + { + guint8 tmp8; + switch (pd->mode) + { + case PWATM_MODE_AAL5_SDU: + DISSECTOR_ASSERT(pd->submode == PWATM_SUBMODE_ADMIN_CELL); + /*fallthrough for ATM admin cell submode only*/ + case PWATM_MODE_N1_CW: + case PWATM_MODE_N1_NOCW: + pd->vpi = (tvb_get_ntohs (tvb, 0) >> 4); + pd->vci = (tvb_get_ntoh24(tvb, 1) >> 4) & 0xffff; + tmp8 = (tvb_get_guint8(tvb, 3)); + pd->pti = (tmp8 >> 1) & 0x07; + pd->cwb3.clp = (tmp8 >> 0) & 0x01; + UPDATE_CUMULATIVE_VALUE(pd->cumulative.vpi,pd->vpi); + UPDATE_CUMULATIVE_VALUE(pd->cumulative.vci,pd->vci); + UPDATE_CUMULATIVE_VALUE(pd->cumulative.pti,pd->pti); + UPDATE_CUMULATIVE_VALUE(pd->cumulative.clp,pd->cwb3.clp); + /* + * OAM cell mode is always used for aal5_sdu/admin_cell mode, + * even if pti indicates user cell. + */ + pd->cell_mode_oam = + (pd->mode == PWATM_MODE_AAL5_SDU && pd->submode == PWATM_SUBMODE_ADMIN_CELL) + || PTI_IS_ADMIN(pd->pti); + break; + case PWATM_MODE_11_VPC: + pd->vci = tvb_get_ntohs(tvb, 1); + UPDATE_CUMULATIVE_VALUE(pd->cumulative.vci,pd->vci); + /*fallthrough*/ + case PWATM_MODE_11_VCC: + tmp8 = (tvb_get_guint8(tvb, 0)); + pd->cwb3.m = (tmp8 >> 7) & 0x1; + pd->cwb3.v = (tmp8 >> 6) & 0x1; + pd->cwb3.rsv = (tmp8 >> 4) & 0x3; + pd->pti = (tmp8 >> 1) & 0x7; + pd->cwb3.clp = (tmp8 >> 0) & 0x1; + UPDATE_CUMULATIVE_VALUE(pd->cumulative.pti,pd->pti); + UPDATE_CUMULATIVE_VALUE(pd->cumulative.clp,pd->cwb3.clp); + /* + * OAM cell mode is possible if packet contains atm cell (m == 0). + */ + pd->cell_mode_oam = PTI_IS_ADMIN(pd->pti) && (pd->cwb3.m == 0); + break; + case PWATM_MODE_AAL5_PDU: + tmp8 = (tvb_get_guint8(tvb, 0)); + pd->cwb3.m = (tmp8 >> 7) & 0x1; + pd->cwb3.v = (tmp8 >> 6) & 0x1; + pd->cwb3.rsv = (tmp8 >> 3) & 0x7; + pd->cwb3.u = (tmp8 >> 2) & 0x1; + pd->cwb3.e = (tmp8 >> 1) & 0x1; + pd->cwb3.clp = (tmp8 >> 0) & 0x1; + UPDATE_CUMULATIVE_VALUE(pd->cumulative.clp,pd->cwb3.clp); + break; + default: + DISSECTOR_ASSERT_NOT_REACHED(); + break; + } + } + + if (tree) + { + proto_item* item; + + item = proto_tree_add_item(tree, proto_cell_header, tvb + ,0 + ,dissect_size + ,FALSE); + if (PWATM_MODE_AAL5_PDU == pd->mode) + { + proto_item_set_text(item, "Third byte of Control Word"); /*overwrite heading line*/ + /* cwb3 fileds are appended to CW heading line, not here */ + } + else + { + proto_item_append_text(item," [%.3d]",pd->pw_cell_number); + proto_item_append_text(item,", "); + if (pd->vpi >= 0) + proto_item_append_text(item, "VPI:%.4u ", (unsigned)(pd->vpi)); + if (pd->vci >= 0) + proto_item_append_text(item, "VCI:%.5u ", (unsigned)(pd->vci)); + if (pd->pti >= 0) + proto_item_append_text(item, "PTI:%.1u ", (unsigned)(pd->pti)); + proto_item_append_text_cwb3_fields(item,pd); + } + + { + proto_tree* tree; + tree = proto_item_add_subtree(item, ett_cell_header); + if (is_enough_data) + { + proto_item* item; + if (MODE_N1(pd->mode) + || (pd->mode == PWATM_MODE_AAL5_SDU && pd->submode == PWATM_SUBMODE_ADMIN_CELL)) + { + (void) proto_tree_add_uint(tree, hf_cell_h_vpi, tvb, 0, 2, (unsigned)pd->vpi); + (void) proto_tree_add_uint(tree, hf_cell_h_vci, tvb, 1, 3, (unsigned)pd->vci); + + item = proto_tree_add_item(tree, hf_cell_h_pti, tvb, 3, 1, FALSE); + if (NULL == match_strval(pd->pti,atm_pt_vals)) + { + expert_add_info_format(pinfo, item, PI_UNDECODED, PI_WARN, + "Unknown value of PTI field (%d) in the ATM cell header", + pd->pti); + } + else if (pd->mode == PWATM_MODE_AAL5_SDU && !PTI_IS_ADMIN(pd->pti)) + { + expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR, + "ATM admin cell is transerred;" + " PTI field (%d) should be 4, 5 or 6.", + pd->pti); + } + + (void) proto_tree_add_item(tree, hf_cell_h_clp, tvb, 3, 1, FALSE); + } + else if (MODE_11_OR_AAL5_PDU(pd->mode)) + { + item = proto_tree_add_item(tree, hf_cell_h_m , tvb, 0, 1, FALSE); + if ((0 != pd->cwb3.m) && MODE_11(pd->mode)) + { + expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR + ,"1:1 mode:" + " M bit must be 0 to distinguish from AAL5 PDU mode"); + } + + item = proto_tree_add_item(tree, hf_cell_h_v , tvb, 0, 1, FALSE); + if ((0 == pd->cwb3.v) && (PWATM_MODE_11_VPC == pd->mode)) + { + expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR + ,"1:1 VPC mode:" + " V bit must be 1 to indicate that VCI is present"); + } + if ((0 != pd->cwb3.v) && (PWATM_MODE_11_VCC == pd->mode)) + { + expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR + ,"1:1 VCC mode:" + " V bit must be 0 to indicate that VCI is absent"); + } + if ((0 != pd->cwb3.v) && (PWATM_MODE_AAL5_PDU == pd->mode)) + { + expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR + ,"AAL5 PDU mode:" + " V bit must be 0 to indicate that VCI is absent"); + } + + item = proto_tree_add_item(tree + ,(PWATM_MODE_AAL5_PDU == pd->mode) + ? hf_aal5_pdu_rsv + : hf_cell_h_rsv + ,tvb, 0, 1, FALSE); + if (0 != pd->cwb3.rsv) + { + expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR + ,"Reserved bits in the 3rd byte of CW must be 0"); + } + else + { + PROTO_ITEM_SET_HIDDEN(item); /*...and show only in error cases */ + } + + if (MODE_11(pd->mode)) + { + item = proto_tree_add_item(tree, hf_cell_h_pti, tvb, 0, 1, FALSE); + if (NULL == match_strval(pd->pti,atm_pt_vals)) + { + expert_add_info_format(pinfo, item, PI_UNDECODED, PI_WARN, + "Unknown value of PTI field (%d) in the atm-specific byte" + ,pd->pti); + } + } + else + { + (void) proto_tree_add_item(tree, hf_aal5_pdu_u, tvb, 0, 1, FALSE); + (void) proto_tree_add_item(tree, hf_aal5_pdu_e, tvb, 0, 1, FALSE); + } + + (void) proto_tree_add_item(tree, hf_cell_h_clp, tvb, 0, 1, FALSE); + + if (PWATM_MODE_11_VPC == pd->mode) + { + (void) proto_tree_add_uint(tree, hf_cell_h_vci, tvb, 1, 2 + ,(unsigned)pd->vci); + } + } + else + { + DISSECTOR_ASSERT_NOT_REACHED(); + } + } + else + { + expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR + ,"Not enough data (size: %d), impossible to decode" + ,(int)dissect_size); + } + } + } + return dissect_size; +} + + +static +int dissect_cell(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree) +{ + gboolean is_enough_data; + int dissect_size; + + { + gint size; + size = tvb_reported_length_remaining(tvb, 0); + if (size < SIZEOF_ATM_CELL_PAYLOAD) + { + is_enough_data = FALSE; + dissect_size = size; + } + else + { + is_enough_data = TRUE; + dissect_size = SIZEOF_ATM_CELL_PAYLOAD; + } + } + + /* + * NB: do not touch columns -- keep info from previous dissector + */ + + if (tree) + { + proto_item* item; + item = proto_tree_add_item(tree, proto_cell, tvb, 0, dissect_size, FALSE); + { + pwatm_private_data_t * pd; + pd = pinfo->private_data; + if (NULL != pd) + { + proto_item_append_text(item," [%.3d]",pd->pw_cell_number); + } + } + pwc_item_append_text_n_items(item,dissect_size,"byte"); + if (!is_enough_data) + { + expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR + ,"Bad length of cell payload: must be == %d" + ,(int)SIZEOF_ATM_CELL_PAYLOAD); + } + + { + proto_tree* tree; + tvbuff_t* tvb_d; + tree = proto_item_add_subtree(item, ett_cell); + tvb_d = tvb_new_subset(tvb, 0, dissect_size, -1); + call_dissector(dh_data, tvb_d, pinfo, tree); + item = proto_tree_add_int(tree, hf_cell_payload_len, tvb, 0, 0, dissect_size); + PROTO_ITEM_SET_HIDDEN(item); + } + } + return dissect_size; +} + + +void proto_register_pw_atm_ata(void) +{ + static const value_string clp_vals[] = { + { 0, "High priority" }, + { 1, "Low priority" }, + { 0, NULL } + }; + static const value_string m_vals[] = { + { 0, "ATM cell" }, + { 1, "AAL5 payload" }, + { 0, NULL } + }; + static const value_string u_vals[] = { + { 0, "This frame does not contain the last cell of AAL5 PDU" }, + { 1, "This frame contains the last cell of AAL5 PDU" }, + { 0, NULL } + }; + static const value_string e_vals[] = { + { 0, "Congestion is not experienced" }, + { 1, "Congestion is experienced for one or more ATM AAL5 cells" }, + { 0, NULL } + }; + static hf_register_info hfa_cell_header[] = { + { &hf_cell_h_vpi ,{"VPI" ,"atm.vpi" + ,FT_UINT16 ,BASE_DEC ,NULL ,0 + ,NULL ,HFILL }} + ,{ &hf_cell_h_vci ,{"VCI" ,"atm.vci" + ,FT_UINT16 ,BASE_DEC ,NULL ,0 + ,NULL ,HFILL }} + ,{ &hf_cell_h_pti ,{"Payload Type" ,"atm.pti" + ,FT_UINT8 ,BASE_DEC ,VALS(atm_pt_vals),0x0e + ,"The 3-bit Payload Type Identifier (PTI) incorporates ATM Layer" + " PTI coding of the cell. These bits are set to the value of the" + " PTI of the encapsulated ATM cell." + ,HFILL }} + ,{ &hf_cell_h_clp ,{"Cell Loss Priority" ,"atm.clp" + ,FT_UINT8 ,BASE_DEC ,VALS(clp_vals) ,0x01 + ,"The Cell Loss Priority (CLP) field indicates CLP value" + " of the encapsulated cell." + ,HFILL }} + ,{ &hf_cell_h_m ,{"Transport Mode" ,"atm.pw_control_byte.m" + ,FT_UINT8 ,BASE_DEC ,VALS(m_vals) ,0x80 + ,"Bit (M) of the control byte indicates whether the packet" + " contains an ATM cell or a frame payload. If set to 0," + " the packet contains an ATM cell. If set to 1, the PDU" + " contains an AAL5 payload." + ,HFILL }} + ,{ &hf_cell_h_v ,{"VCI Present" ,"atm.pw_control_byte.v" + ,FT_BOOLEAN ,8 ,TFS(&tfs_yes_no),0x40 + ,"Bit (V) of the control byte indicates whether the VCI field" + " is present in the packet. If set to 1, the VCI field is present" + " for the cell. If set to 0, no VCI field is present." + ,HFILL }} + ,{ &hf_cell_h_rsv ,{"Reserved bits" ,"atm.pw_control_byte.rsv" + ,FT_UINT8 ,BASE_DEC ,NULL ,0x30 + ,"The reserved bits should be set to 0 at the transmitter and" + " ignored upon reception." + ,HFILL }} + ,{ &hf_aal5_pdu_rsv ,{"Reserved bits" ,"atm.pw_control_byte.rsv" + ,FT_UINT8 ,BASE_DEC ,NULL ,0x38 + ,"The reserved bits should be set to 0 at the transmitter and" + " ignored upon reception." + ,HFILL }} + ,{ &hf_aal5_pdu_u ,{"U bit" ,"atm.pw_control_byte.u" + ,FT_UINT8 ,BASE_DEC ,VALS(u_vals) ,0x04 + ,"Indicates whether this frame contains the last cell of" + " an AAL5 PDU and represents the value of the ATM User-to-User" + " bit for the last ATM cell of the PSN frame. Note: The ATM" + " User-to-User bit is the least significant bit of the PTI" + " in the ATM header." + ,HFILL }} + ,{ &hf_aal5_pdu_e ,{"EFCI" ,"atm.pw_control_byte.efci" + ,FT_UINT8 ,BASE_DEC ,VALS(e_vals) ,0x02 + ,"EFCI is set to the EFCI state of the last cell of the" + " AAL5 PDU or AAL5 fragment. Note: The EFCI state is" + " indicated in the middle bit of each ATM cell's PTI." + ,HFILL }} + }; +static hf_register_info hfa_cell[] = { + {&hf_cell_payload_len ,{"Length" ,"atm.cell.len" + ,FT_INT32 ,BASE_DEC ,NULL ,0 + ,NULL ,HFILL }} + }; + + #define HF_INITIALIZER_NCELLS(hf_handle)\ + {&(hf_handle) ,{"Number of good encapsulated cells","pw.atm.cells"\ + ,FT_INT32 ,BASE_DEC ,NULL ,0\ + ,NULL ,HFILL }} + + #define HF_INITIALIZER_PWTYPE(hf_handle,name)\ + { &hf_handle ,{name ,name\ + ,FT_BOOLEAN ,0 ,NULL ,0x0\ + ,"Identifies type of ATM PW. May be used for filtering.",HFILL}} + + + static hf_register_info hfa_n1_nocw[] = { + HF_INITIALIZER_NCELLS(hf_n1_nocw_ncells) + ,HF_INITIALIZER_PWTYPE(hf_pw_type_n1_nocw,"pw.type.atm.n1nocw") + }; + + static hf_register_info hfa_n1_cw[] = { + HF_INITIALIZER_NCELLS(hf_n1_cw_ncells) + ,HF_INITIALIZER_PWTYPE(hf_pw_type_n1_cw,"pw.type.atm.n1cw") + }; + + static hf_register_info hfa_11_aal5pdu[] = { + HF_INITIALIZER_NCELLS(hf_11_ncells) + ,HF_INITIALIZER_PWTYPE(hf_pw_type_11_vcc,"pw.type.atm.11vcc") + ,HF_INITIALIZER_PWTYPE(hf_pw_type_11_vpc,"pw.type.atm.11vpc") + ,HF_INITIALIZER_PWTYPE(hf_pw_type_aal5_pdu,"pw.type.atm.aal5pdu") + }; + + static hf_register_info hfa_aal5_sdu[] = { + HF_INITIALIZER_PWTYPE(hf_pw_type_aal5_sdu,"pw.type.atm.aal5sdu") + }; + + static const value_string a5s_t_vals[] = { + { 0, "AAL5 payload" }, + { 1, "ATM admin cell" }, + { 0, NULL } + }; + + static const value_string a5s_e_vals[] = { + { 0, "No congestion" }, + { 1, "Congestion experienced" }, + { 0, NULL } + }; + + static hf_register_info hfa_cw[] = { + { &hf_cw_bits03 ,{"Bits 0 to 3" ,"pw.cw.bits03" + ,FT_UINT8 ,BASE_HEX ,NULL ,0xf0 + ,NULL ,HFILL }} + ,{ &hf_pref_cw_flags ,{"Flags" ,"pw.cw.flags" + ,FT_UINT8 ,BASE_HEX ,NULL ,0x0f + ,NULL ,HFILL }} + ,{ &hf_pref_cw_a5s_t ,{"Payload type" ,"atm.pt" + ,FT_UINT8 ,BASE_DEC ,VALS(a5s_t_vals),0x08 + ,"Bit (T) of the control word indicates whether the packet contains" + " an ATM admin cell or an AAL5 payload. If T = 1, the packet" + " contains an ATM admin cell, encapsulated according to the N:1" + " cell relay encapsulation. If not set, the PDU" + " contains an AAL5 payload." + ,HFILL }} + ,{ &hf_pref_cw_a5s_e ,{"EFCI bit" ,"atm.efci" + ,FT_UINT8 ,BASE_DEC ,VALS(a5s_e_vals),0x04 + ,"The ingress router sets this bit to 1 if the EFCI bit" + " of the final cell of those that transported the AAL5 CPCS-SDU is" + " set to 1, or if the EFCI bit of the single ATM cell to be" + " transported in the packet is set to 1. Otherwise, this bit" + " is set to 0." + ,HFILL }} + ,{ &hf_pref_cw_a5s_c ,{"CLP bit" ,"atm.clp" + ,FT_UINT8 ,BASE_DEC ,VALS(clp_vals) ,0x02 + ,"The ingress router sets this bit to 1 if the CLP bit" + " of any of the ATM cells that transported the AAL5 CPCS-SDU is set" + " to 1, or if the CLP bit of the single ATM cell to be transported" + " in the packet is set to 1. Otherwise this bit is set to 0." + ,HFILL }} + ,{ &hf_pref_cw_a5s_u ,{"U bit (Command/Response)" ,"pw.cw.aal5sdu.u" + ,FT_UINT8 ,BASE_DEC ,NULL ,0x01 + ,"When FRF.8.1 Frame Relay/ATM PVC Service Interworking [RFC3916]" + " traffic is being transported, the Least-Significant Bit of CPCS-UU" + " of the AAL5 CPCS-PDU may contain the Frame Relay C/R bit." + " The ingress router copies this bit here." + ,HFILL }} + ,{ &hf_pref_cw_rsv ,{"Reserved bits" ,"pw.cw.rsv" + ,FT_UINT8 ,BASE_DEC ,NULL ,0xc0 + ,NULL ,HFILL }} + ,{ &hf_generic_cw_rsv ,{"Reserved bits" ,"pw.cw.rsv" + ,FT_UINT8 ,BASE_DEC ,NULL ,0x0f + ,NULL ,HFILL }} + ,{ &hf_pref_cw_len ,{"Length" ,"pw.cw.length" + ,FT_UINT8 ,BASE_DEC ,NULL ,0x3f + ,NULL ,HFILL }} + ,{ &hf_pref_cw_rsvlen ,{"Length (extended)" ,"pw.cw.length" + ,FT_UINT8 ,BASE_DEC ,NULL ,0xff + ,NULL ,HFILL }} + ,{ &hf_cw_seq ,{"Sequence number" ,"pw.cw.seqno" + ,FT_UINT16 ,BASE_DEC ,NULL ,0 + ,NULL ,HFILL }} + ,{ &hf_gen_cw_atmbyte ,{"ATM-specific byte" ,"pw.cw.3rd_byte" + ,FT_UINT8 ,BASE_HEX ,NULL ,0xFF + ,NULL ,HFILL }} + }; + static gint *ett_array[] = { + &ett_encaps + ,&ett_cw + ,&ett_cell_header + ,&ett_cell + }; + + proto_n1_cw = + proto_register_protocol(pwc_longname_pw_atm_n1_cw + ,shortname_n1_cw + ,"mplspwatmn1cw"); + proto_11_or_aal5_pdu = + proto_register_protocol(pwc_longname_pw_atm_11_or_aal5_pdu + ,shortname_11_or_aal5_pdu + ,"mplspwatm11_or_aal5pdu"); + proto_aal5_sdu = + proto_register_protocol(pwc_longname_pw_atm_aal5_sdu + ,shortname_aal5_sdu + ,"mplspwatmaal5sdu"); + proto_n1_nocw = + proto_register_protocol(pwc_longname_pw_atm_n1_nocw + ,shortname_n1_nocw + ,"mplspwatmn1nocw"); + proto_control_word = + proto_register_protocol("MPLS PW ATM Control Word" + ,"MPLS PW ATM Control Word" + ,"mplspwatmcontrolword"); + proto_cell_header = + proto_register_protocol("MPLS PW ATM Cell Header" + ,"MPLS PW ATM Cell Header" + ,"mplspwatmcellheader"); + proto_cell = + proto_register_protocol("ATM Cell" + ,"ATM Cell" + ,"mplspwatmcell"); + + proto_register_field_array( proto_cell ,hfa_cell ,array_length(hfa_cell)); + proto_register_field_array( proto_cell_header ,hfa_cell_header,array_length(hfa_cell_header)); + proto_register_field_array( proto_control_word ,hfa_cw ,array_length(hfa_cw)); + proto_register_field_array( proto_n1_nocw ,hfa_n1_nocw ,array_length(hfa_n1_nocw)); + proto_register_field_array( proto_n1_cw ,hfa_n1_cw ,array_length(hfa_n1_cw)); + proto_register_field_array( proto_11_or_aal5_pdu ,hfa_11_aal5pdu ,array_length(hfa_11_aal5pdu)); + proto_register_field_array( proto_aal5_sdu ,hfa_aal5_sdu ,array_length(hfa_aal5_sdu)); + + proto_register_subtree_array(ett_array, array_length(ett_array)); + + register_dissector("mpls_pw_atm_aal5_sdu" ,dissect_aal5_sdu ,proto_aal5_sdu); + register_dissector("mpls_pw_atm_11_or_aal5_pdu" ,dissect_11_or_aal5_pdu ,proto_11_or_aal5_pdu); + register_dissector("mpls_pw_atm_n1_cw" ,dissect_n1_cw ,proto_n1_cw); + register_dissector("mpls_pw_atm_n1_nocw" ,dissect_n1_nocw ,proto_n1_nocw); + register_dissector("mpls_pw_atm_control_word" ,dissect_control_word ,proto_control_word); + new_register_dissector("mpls_pw_atm_cell" ,dissect_cell ,proto_cell); + new_register_dissector("mpls_pw_atm_cell_header",dissect_cell_header ,proto_cell_header); + { + static const char description_allow_cw_length_nonzero[] = + "Enable to allow non-zero Length in Control Word." + " This may be needed to correctly decode traffic from some legacy devices" + " which generate non-zero Length even if there is no padding in the packet." + " Note that Length should have proper value (dissector checks this anyway)." + "\n\n" + "Disable to blame all packets with CW.Length <> 0. This conforms to RFC4717." + ; + static const char description_extend_cw_length_with_rsvd[] = + "Enable to use reserved bits (8..9) of Control Word as an extension of CW.Length." + " This may be needed to correctly decode traffic from some legacy devices" + " which uses reserved bits as extension of Length" + "\n\n" + "Disable to blame all packets with CW.Reserved <> 0. This conforms to RFC4717." + ; + module_t * module_n1_cw; + module_t * module_aal5_sdu; + + module_n1_cw = prefs_register_protocol(proto_n1_cw,NULL); + prefs_register_bool_preference(module_n1_cw + ,"allow_cw_length_nonzero" + ,"Allow CW.Length <> 0" + ,&description_allow_cw_length_nonzero[0] + ,&pref_n1_cw_allow_cw_length_nonzero); + prefs_register_bool_preference(module_n1_cw + ,"extend_cw_length_with_rsvd" + ,"Use CW.Reserved as extension of CW.Length" + ,&description_extend_cw_length_with_rsvd[0] + ,&pref_n1_cw_extend_cw_length_with_rsvd); + + module_aal5_sdu = prefs_register_protocol(proto_aal5_sdu,NULL); + prefs_register_bool_preference(module_aal5_sdu + ,"allow_cw_length_nonzero_aal5" + ,"Allow CW.Length <> 0" + ,&description_allow_cw_length_nonzero[0] + ,&pref_aal5_sdu_allow_cw_length_nonzero); + prefs_register_bool_preference(module_aal5_sdu + ,"extend_cw_length_with_rsvd_aal5" + ,"Use CW.Reserved as extension of CW.Length" + ,&description_extend_cw_length_with_rsvd[0] + ,&pref_aal5_sdu_extend_cw_length_with_rsvd); + } +} + + +void proto_reg_handoff_pw_atm_ata(void) +{ + dissector_handle_t h; + h = find_dissector("mpls_pw_atm_n1_cw"); + dissector_add( "mpls.label", LABEL_INVALID, h ); + h = find_dissector("mpls_pw_atm_n1_nocw"); + dissector_add( "mpls.label", LABEL_INVALID, h ); + h = find_dissector("mpls_pw_atm_11_or_aal5_pdu"); + dissector_add( "mpls.label", LABEL_INVALID, h ); + h = find_dissector("mpls_pw_atm_aal5_sdu"); + dissector_add( "mpls.label", LABEL_INVALID, h ); - data_h = find_dissector("data"); - atm_h = find_dissector("atm_4717"); + dh_cell = find_dissector("mpls_pw_atm_cell"); + dh_cell_header = find_dissector("mpls_pw_atm_cell_header"); + dh_control_word = find_dissector("mpls_pw_atm_control_word"); + dh_atm_truncated = find_dissector("atm_truncated"); + dh_atm_untruncated = find_dissector("atm_untruncated"); + dh_atm_oam_cell = find_dissector("atm_oam_cell"); + dh_padding = find_dissector("pw_padding"); + dh_data = find_dissector("data"); } diff --git a/epan/dissectors/packet-pw-atm.h b/epan/dissectors/packet-pw-atm.h new file mode 100644 index 0000000000..d1b0346b25 --- /dev/null +++ b/epan/dissectors/packet-pw-atm.h @@ -0,0 +1,101 @@ +/* packet-pw-atm.h + * Interface of pw-atm module + * Copyright 2009, Artem Tamazov <artem.tamazov@tellabs.com> + * + * $Id$ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 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. + */ + +#ifndef PACKET_PW_ATM_H +#define PACKET_PW_ATM_H + +#include "packet-pw-common.h" + +typedef enum { + PWATM_MODE_UNKNOWN = 0 + ,PWATM_MODE_N1_NOCW + ,PWATM_MODE_N1_CW + ,PWATM_MODE_11_VCC + ,PWATM_MODE_11_VPC + ,PWATM_MODE_AAL5_SDU + ,PWATM_MODE_AAL5_PDU +} pwatm_mode_t; + +typedef enum { + PWATM_SUBMODE_DEFAULT = 0 + ,PWATM_SUBMODE_ADMIN_CELL /*used in aal5_sdu dissector only*/ +} pwatm_submode_t; + +typedef struct { + int pw_cell_number; + pwc_packet_properties_t props; + gint packet_size; + pwatm_mode_t mode; + pwatm_submode_t submode; + struct { + /* + * ATM-specific attributes which remain the same + * across all the cells in the pw packet. Values are filled + * by sub-dissectors and read by upper-level dissector. + * Meanings of values: + * (-1) - value is unknown + * (-2) - value is different among cells + * positive - value is the same in all cells + * Machinery is implemented in the UPDATE_CUMULATIVE_VALUE macro. + */ + gint32 vpi; + gint32 vci; + gint32 clp; + gint32 pti; + } cumulative; + gint32 vpi; /*-1 if unknown*/ + gint32 vci; /*-1 if unknown*/ + gint32 pti; /*-1 if unknown*/ + struct { + /* + * Some fields from 3rd byte of CW. Filled by cell_header dissector. + * In in AAL5 PDU mode, this allows control_word dissector to print + * these values in the CW heading line in the tree. + * Meanings of values: + * (-1) - value is unknown + */ + gint32 m; + gint32 v; + gint32 rsv; + gint32 u; + gint32 e; + gint32 clp; + } cwb3; + gboolean aal5_sdu_frame_relay_cr_bit; /*see rfc4717 10.1*/ + gboolean cell_mode_oam; /*atm admin cell*/ + gboolean enable_fill_columns_by_atm_dissector; +} pwatm_private_data_t; + + +#define PWATM_PRIVATE_DATA_T_INITIALIZER { \ + 0, PWC_PACKET_PROPERTIES_T_INITIALIZER, 0 \ + ,PWATM_MODE_UNKNOWN, PWATM_SUBMODE_DEFAULT \ + ,{-1, -1, -1, -1 } \ + ,-1, -1, -1 \ + ,{-1, -1, -1, -1, -1, -1 } \ + ,FALSE, FALSE, TRUE \ + } + +#endif /*PACKET_PW_ATM_H*/ diff --git a/epan/dissectors/packet-pw-cesopsn.c b/epan/dissectors/packet-pw-cesopsn.c index e8656adb1a..be77883010 100644 --- a/epan/dissectors/packet-pw-cesopsn.c +++ b/epan/dissectors/packet-pw-cesopsn.c @@ -56,12 +56,12 @@ static int hf_cw_frg = -1; static int hf_cw_len = -1; static int hf_cw_seq = -1; static int hf_payload = -1; -static int hf_padding = -1; -static int hf_padding_f = -1; +static int hf_payload_l = -1; static dissector_handle_t data_handle; +static dissector_handle_t pw_padding_handle; -static const char pwc_longname_pw_cesopsn[] = "CESoPSN basic NxDS0 mode (no RTP support)"; +const char pwc_longname_pw_cesopsn[] = "CESoPSN basic NxDS0 mode (no RTP support)"; static const char shortname[] = "CESoPSN basic (no RTP)"; static const value_string vals_cw_lm[] = { @@ -121,7 +121,7 @@ static void dissect_pw_cesopsn( tvbuff_t * tvb_original, packet_info * pinfo, pr /* check how "good" is this packet */ /* also decide payload length from packet size and CW */ - properties = 0; + properties = PWC_PACKET_PROPERTIES_T_INITIALIZER; if (0 != (tvb_get_guint8(tvb_original, 0) & 0xf0 /*bits03*/)) { properties |= PWC_CW_BAD_BITS03; @@ -188,7 +188,7 @@ static void dissect_pw_cesopsn( tvbuff_t * tvb_original, packet_info * pinfo, pr { guint8 cw_lm; cw_lm = tvb_get_guint8(tvb_original, 0) & 0x0b /*l+mod*/; - if (!pwc_value_listed_in_vals(cw_lm, vals_cw_lm)) + if (NULL == match_strval(cw_lm, vals_cw_lm)) { properties |= PWC_CW_SUSPECT_LM; } @@ -348,6 +348,9 @@ static void dissect_pw_cesopsn( tvbuff_t * tvb_original, packet_info * pinfo, pr } tree = proto_item_add_subtree(item, ett); call_dissector(data_handle, tvb, pinfo, tree); + item = proto_tree_add_int(tree, hf_payload_l, tvb, 0, 0 + ,(int)payload_size); /* allow filtering */ + PROTO_ITEM_SET_HIDDEN(item); } } @@ -357,12 +360,9 @@ static void dissect_pw_cesopsn( tvbuff_t * tvb_original, packet_info * pinfo, pr proto_tree* tree; tree = proto_item_add_subtree(item, ett); { - proto_item* item; tvbuff_t* tvb; tvb = tvb_new_subset(tvb_original, PWC_SIZEOF_CW + payload_size, padding_size, -1); - item = proto_tree_add_item(tree, hf_padding, tvb, 0, -1, FALSE); - pwc_item_append_text_n_items(item,(int)padding_size,"octet"); - call_dissector(data_handle, tvb, pinfo, tree); + call_dissector(pw_padding_handle, tvb, pinfo, tree); } } } @@ -396,11 +396,8 @@ void proto_register_pw_cesopsn(void) ,{&hf_payload ,{"TDM payload" ,"pwcesopsn.payload" ,FT_BYTES ,BASE_NONE ,NULL ,0 ,NULL ,HFILL }} - ,{&hf_padding ,{"Padding" ,"pwcesopsn.padding" - ,FT_BYTES ,BASE_NONE ,NULL - ,0 ,NULL ,HFILL }} - ,{&hf_padding_f ,{"Padding (formatted)" ,"" - ,FT_BYTES ,BASE_NONE ,NULL + ,{&hf_payload_l ,{"TDM payload length" ,"pwcesopsn.payload.len" + ,FT_INT32 ,BASE_DEC ,NULL ,0 ,NULL ,HFILL }} }; @@ -420,6 +417,7 @@ void proto_reg_handoff_pw_cesopsn(void) dissector_handle_t h; h = find_dissector("pw_cesopsn"); data_handle = find_dissector("data"); + pw_padding_handle = find_dissector("pw_padding"); dissector_add("mpls.label", LABEL_INVALID, h); return; } diff --git a/epan/dissectors/packet-pw-common.c b/epan/dissectors/packet-pw-common.c index 21f88ef016..e879e02e41 100644 --- a/epan/dissectors/packet-pw-common.c +++ b/epan/dissectors/packet-pw-common.c @@ -28,6 +28,7 @@ #endif #include <string.h> +#include <epan/packet.h> #include "packet-pw-common.h" static const char string_ok[] = "Ok"; @@ -57,22 +58,6 @@ pwc_vals_cw_frag[] = { }; -int pwc_value_listed_in_vals(const guint32 val, const value_string * vals) -{ - if (NULL != vals) - { - while (vals->strptr != NULL) - { - if (val == vals->value) - { - return (1==1); - } - ++vals; - } - } - return 0; -} - void pwc_item_append_cw(proto_item* item, const guint32 cw, const gboolean append_text) { if (item != NULL) @@ -90,8 +75,61 @@ void pwc_item_append_cw(proto_item* item, const guint32 cw, const gboolean appen void pwc_item_append_text_n_items(proto_item* item, const int n, const char * const item_text) { assert(item != 0); - proto_item_append_text(item, ", %d %s%s", n, item_text, plurality(n,"","s")); + if (n >=0) + { + proto_item_append_text(item, ", %d %s%s", n, item_text, plurality(n,"","s")); + } + return; +} + + +static gint proto_pw_padding = -1; +static gint ett = -1; +static int hf_padding_len = -1; +static dissector_handle_t dh_data; + +static +void dissect_pw_padding(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree) +{ + /* do not touch columns */ + if (tree) + { + gint size; + proto_item* item; + size = tvb_reported_length_remaining(tvb, 0); + item = proto_tree_add_item(tree, proto_pw_padding, tvb, 0, -1, FALSE); + pwc_item_append_text_n_items(item,size,"byte"); + { + proto_tree* tree; + tree = proto_item_add_subtree(item, ett); + call_dissector(dh_data, tvb, pinfo, tree); + item = proto_tree_add_int(tree, hf_padding_len, tvb, 0, 0, size); + PROTO_ITEM_SET_HIDDEN(item); /*allow filtering*/ + } + } + return; +} + +void proto_register_pw_padding(void) +{ + static hf_register_info hfpadding[] = { + {&hf_padding_len ,{"Length" ,"pw.padding.len" + ,FT_INT32 ,BASE_DEC ,NULL ,0 + ,NULL ,HFILL }} + }; + static gint *ett_array[] = { + &ett + }; + proto_pw_padding = proto_register_protocol("Pseudowire Padding","PW Padding","pwpadding"); + proto_register_field_array(proto_pw_padding, hfpadding, array_length(hfpadding)); + proto_register_subtree_array(ett_array, array_length(ett_array)); + register_dissector("pw_padding", dissect_pw_padding, proto_pw_padding); return; } +void proto_reg_handoff_pw_padding(void) +{ + dh_data = find_dissector("data"); + return; +} diff --git a/epan/dissectors/packet-pw-common.h b/epan/dissectors/packet-pw-common.h index 81f6b99a73..bf8b99060b 100644 --- a/epan/dissectors/packet-pw-common.h +++ b/epan/dissectors/packet-pw-common.h @@ -31,6 +31,13 @@ #define PWC_SIZEOF_CW 4 +extern const char pwc_longname_pw_satop[]; +extern const char pwc_longname_pw_cesopsn[]; +extern const char pwc_longname_pw_atm_n1_cw[]; +extern const char pwc_longname_pw_atm_n1_nocw[]; +extern const char pwc_longname_pw_atm_11_or_aal5_pdu[]; +extern const char pwc_longname_pw_atm_aal5_sdu[]; + extern const value_string pwc_vals_cw_l_bit[]; extern const value_string pwc_vals_cw_r_bit[]; extern const value_string pwc_vals_cw_frag[]; @@ -42,19 +49,26 @@ typedef enum { ,PWC_CW_BAD_LEN_MUST_BE_0 = 1 << 3 ,PWC_CW_BAD_FRAG = 1 << 4 ,PWC_CW_BAD_RSV = 1 << 5 + ,PWC_CW_BAD_FLAGS = 1 << 8 + ,PWC_CW_BAD_PAYLEN_LE_0 = 1 << 9 + ,PWC_CW_BAD_PADDING_NE_0 = 1 << 10 ,PWC_ANYOF_CW_BAD = PWC_CW_BAD_BITS03 + PWC_CW_BAD_PAYLEN_LT_0 + PWC_CW_BAD_PAYLEN_GT_PACKET + PWC_CW_BAD_LEN_MUST_BE_0 + PWC_CW_BAD_FRAG + PWC_CW_BAD_RSV + + PWC_CW_BAD_FLAGS + + PWC_CW_BAD_PAYLEN_LE_0 + + PWC_CW_BAD_PADDING_NE_0 ,PWC_CW_SUSPECT_LM = 1 << 6 ,PWC_ANYOF_CW_SUSPECT = PWC_CW_SUSPECT_LM ,PWC_PAY_SIZE_BAD = 1 << 7 -} pwc_packet_properties_t; +} +pwc_packet_properties_t; +#define PWC_PACKET_PROPERTIES_T_INITIALIZER 0 extern void pwc_item_append_cw(proto_item* item, const guint32 cw, const gboolean append_text); extern void pwc_item_append_text_n_items(proto_item* item, const int n, const char * const item_text); -extern int pwc_value_listed_in_vals(const guint32 val, const value_string * vals); #endif diff --git a/epan/dissectors/packet-pw-satop.c b/epan/dissectors/packet-pw-satop.c index 65eacb6a9b..5db068eb1f 100644 --- a/epan/dissectors/packet-pw-satop.c +++ b/epan/dissectors/packet-pw-satop.c @@ -56,12 +56,12 @@ static int hf_cw_frg = -1; static int hf_cw_len = -1; static int hf_cw_seq = -1; static int hf_payload = -1; -static int hf_padding = -1; -static int hf_padding_f = -1; +static int hf_payload_l = -1; static dissector_handle_t data_handle; +static dissector_handle_t pw_padding_handle; -static const char pwc_longname_pw_satop[] = "SAToP (no RTP support)"; +const char pwc_longname_pw_satop[] = "SAToP (no RTP support)"; static const char shortname[] = "SAToP (no RTP)"; @@ -80,7 +80,7 @@ static void dissect_pw_satop(tvbuff_t * tvb_original, packet_info * pinfo, proto ,PAY_LIKE_OCTET_ALIGNED_T1 } payload_properties; - properties = 0; + properties = PWC_PACKET_PROPERTIES_T_INITIALIZER; payload_properties = PAY_NO_IDEA; packet_size = tvb_reported_length_remaining(tvb_original, 0); /* @@ -364,6 +364,9 @@ static void dissect_pw_satop(tvbuff_t * tvb_original, packet_info * pinfo, proto proto_item_append_text(item, "%s", s); tree = proto_item_add_subtree(item, ett); call_dissector(data_handle, tvb, pinfo, tree); + item = proto_tree_add_int(tree, hf_payload_l, tvb, 0, 0 + ,(int)payload_size); /* allow filtering */ + PROTO_ITEM_SET_HIDDEN(item); } } } @@ -374,16 +377,9 @@ static void dissect_pw_satop(tvbuff_t * tvb_original, packet_info * pinfo, proto proto_tree* tree; tree = proto_item_add_subtree(item, ett); { - proto_item* item; tvbuff_t* tvb; tvb = tvb_new_subset(tvb_original, PWC_SIZEOF_CW + payload_size, padding_size, -1); - item = proto_tree_add_item(tree, hf_padding, tvb, 0, -1, FALSE); - pwc_item_append_text_n_items(item,(int)padding_size,"octet"); - { - proto_tree* tree; - tree = proto_item_add_subtree(item, ett); - call_dissector(data_handle, tvb, pinfo, tree); - } + call_dissector(pw_padding_handle, tvb, pinfo, tree); } } } @@ -421,11 +417,8 @@ void proto_register_pw_satop(void) ,{&hf_payload ,{"TDM payload" ,"pwsatop.payload" ,FT_BYTES ,BASE_NONE ,NULL ,0 ,NULL ,HFILL }} - ,{&hf_padding ,{"Padding" ,"pwsatop.padding" - ,FT_BYTES ,BASE_NONE ,NULL - ,0 ,NULL ,HFILL }} - ,{&hf_padding_f ,{"Padding (formatted)" ,"" - ,FT_BYTES ,BASE_NONE ,NULL + ,{&hf_payload_l ,{"TDM payload length" ,"pwsatop.payload.len" + ,FT_INT32 ,BASE_DEC ,NULL ,0 ,NULL ,HFILL }} }; @@ -445,5 +438,6 @@ void proto_reg_handoff_pw_satop(void) dissector_handle_t h; h = find_dissector("pw_satop"); data_handle = find_dissector("data"); + pw_padding_handle = find_dissector("pw_padding"); dissector_add("mpls.label", LABEL_INVALID, h); } |