Wireshark-dev: Re: [Wireshark-dev] Adding CFM plugin and requesting review.

From: keith mercer <maulkin@xxxxxxxx>
Date: Fri, 21 Dec 2007 21:13:27 -0800 (PST)
Hey Alex,
 
I have already coded up the CFM protocol in the recently release version of Wireshark v0.99.7.  The source code is under the packet-cfm.c file in the /epan/dissectors directory.  It includes both the IEEE and the ITU current recommendations of the specification.
 
Cheers,
--Keith


----- Original Message ----
From: alex rozin <arozin@xxxxxxx>
To: maulkin@xxxxxxxx
Sent: Wednesday, December 19, 2007 2:21:29 AM
Subject: [Wireshark-dev] Adding CFM plugin and requesting review.

Hi,
I am a newby in wireshark (while in ethereal I participated in MSTP
dissector).
I looked for an option to debug my 802.1ag implementation and found some
code in
http://www.mail-archive.com/wireshark-dev@xxxxxxxxxxxxx/msg07229/packet-ieee8021ag.c

Good work!
I fixed a few of little bugs in this code and supplemented it with TLV
parsing, LBM/LBR, DMM/DMR and LTM/LTR. I also did operation code
oriented parsing of the field FLAGS.

The patch I attached to this message.
Let me know if you want to have the complete file instead of a patch.
Sure you free to use it at your discretion. I'd be glad to have it in a
next version of wireshark.

Thanks & regards,
Alex



-----Inline Attachment Follows-----

diff -rBbNu wireshark-0.99.6/epan/dissectors/Makefile.common wireshark-0.99.6.new/epan/dissectors/Makefile.common
--- wireshark-0.99.6/epan/dissectors/Makefile.common    2007-07-05 22:24:58.000000000 +0300
+++ wireshark-0.99.6.new/epan/dissectors/Makefile.common    2007-12-13 11:13:40.000000000 +0200
@@ -228,6 +228,7 @@
    packet-catapult-dct2000.c \
    packet-ccsds.c        \
    packet-cdp.c        \
+    packet-ieee8021ag.c        \
    packet-cgmp.c        \
    packet-chdlc.c        \
    packet-cigi.c      \
@@ -753,6 +754,7 @@
    packet-scsi-osd.c    \
    packet-sctp.c        \
    packet-ssl-utils.c    \
+    packet-ieee8021ag.c        \
    packet-user_encap.c

# corresponding headers
diff -rBbNu wireshark-0.99.6/epan/dissectors/Makefile.in wireshark-0.99.6.new/epan/dissectors/Makefile.in
--- wireshark-0.99.6/epan/dissectors/Makefile.in    2007-07-05 22:26:07.000000000 +0300
+++ wireshark-0.99.6.new/epan/dissectors/Makefile.in    2007-12-13 11:15:51.000000000 +0200
@@ -211,6 +211,7 @@
    libcleandissectors_la-packet-catapult-dct2000.lo \
    libcleandissectors_la-packet-ccsds.lo \
    libcleandissectors_la-packet-cdp.lo \
+    libcleandissectors_la-packet-ieee8021ag.lo \
    libcleandissectors_la-packet-cgmp.lo \
    libcleandissectors_la-packet-chdlc.lo \
    libcleandissectors_la-packet-cigi.lo \
@@ -1218,6 +1219,7 @@
    packet-catapult-dct2000.c \
    packet-ccsds.c        \
    packet-cdp.c        \
+    packet-ieee8021ag.c        \
    packet-cgmp.c        \
    packet-chdlc.c        \
    packet-cigi.c      \
@@ -2258,6 +2260,7 @@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcleandissectors_la-packet-catapult-dct2000.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcleandissectors_la-packet-ccsds.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcleandissectors_la-packet-cdp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcleandissectors_la-packet-ieee8021ag.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcleandissectors_la-packet-cgmp.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcleandissectors_la-packet-chdlc.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcleandissectors_la-packet-cigi.Plo@am__quote@
@@ -3471,6 +3474,13 @@
@AMDEP_TRUE@@am__fastdepCC_FALSE@    DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@    $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcleandissectors_la_CFLAGS) $(CFLAGS) -c -o libcleandissectors_la-packet-cdp.lo `test -f 'packet-cdp.c' || echo '$(srcdir)/'`packet-cdp.c

+libcleandissectors_la-packet-ieee8021ag.lo: packet-ieee8021ag.c
+@am__fastdepCC_TRUE@    if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcleandissectors_la_CFLAGS) $(CFLAGS) -MT libcleandissectors_la-packet-ieee8021ag.lo -MD -MP -MF "$(DEPDIR)/libcleandissectors_la-packet-ieee8021ag.Tpo" -c -o libcleandissectors_la-packet-ieee8021ag.lo `test -f 'packet-ieee8021ag.c' || echo '$(srcdir)/'`packet-ieee8021ag.c; \
+@am__fastdepCC_TRUE@    then mv -f "$(DEPDIR)/libcleandissectors_la-packet-ieee8021ag.Tpo" "$(DEPDIR)/libcleandissectors_la-packet-ieee8021ag.Plo"; else rm -f "$(DEPDIR)/libcleandissectors_la-packet-ieee8021ag.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@    source='packet-ieee8021ag.c' object='libcleandissectors_la-packet-ieee8021ag.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@    DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@    $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcleandissectors_la_CFLAGS) $(CFLAGS) -c -o libcleandissectors_la-packet-ieee8021ag.lo `test -f 'packet-ieee8021ag.c' || echo '$(srcdir)/'`packet-ieee8021ag.c
+
libcleandissectors_la-packet-cgmp.lo: packet-cgmp.c
@am__fastdepCC_TRUE@    if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcleandissectors_la_CFLAGS) $(CFLAGS) -MT libcleandissectors_la-packet-cgmp.lo -MD -MP -MF "$(DEPDIR)/libcleandissectors_la-packet-cgmp.Tpo" -c -o libcleandissectors_la-packet-cgmp.lo `test -f 'packet-cgmp.c' || echo '$(srcdir)/'`packet-cgmp.c; \
@am__fastdepCC_TRUE@    then mv -f "$(DEPDIR)/libcleandissectors_la-packet-cgmp.Tpo" "$(DEPDIR)/libcleandissectors_la-packet-cgmp.Plo"; else rm -f "$(DEPDIR)/libcleandissectors_la-packet-cgmp.Tpo"; exit 1; fi
diff -rBbNu wireshark-0.99.6/epan/dissectors/packet-chdlc.c wireshark-0.99.6.new/epan/dissectors/packet-chdlc.c
--- wireshark-0.99.6/epan/dissectors/packet-chdlc.c    2007-07-05 22:25:03.000000000 +0300
+++ wireshark-0.99.6.new/epan/dissectors/packet-chdlc.c    2007-12-13 13:50:19.000000000 +0200
@@ -103,6 +103,7 @@
    {CHDLCTYPE_OSI,        "OSI" },
    {ETHERTYPE_MPLS,      "MPLS unicast"},
    {ETHERTYPE_MPLS_MULTI, "MPLS multicast"},
+    {ETHERTYPE_IEEE_802_1AG, "802.1ag CFM"},
    {0,                    NULL}
};

diff -rBbNu wireshark-0.99.6/epan/dissectors/packet-ethertype.c wireshark-0.99.6.new/epan/dissectors/packet-ethertype.c
--- wireshark-0.99.6/epan/dissectors/packet-ethertype.c    2007-07-05 22:24:56.000000000 +0300
+++ wireshark-0.99.6.new/epan/dissectors/packet-ethertype.c     2007-12-13 13:53:14.000000000 +0200
@@ -131,6 +131,7 @@
    {PPP_PAP,            "PPP Password Authentication Protocol" },
    {PPP_CCP,            "PPP Compression Control Protocol" },
    {ETHERTYPE_LLT,        "Veritas Low Latency Transport (not officially registered)"},
+    {ETHERTYPE_IEEE_802_1AG, "802.1ag CFM"},
    {ETHERTYPE_FCOE,        "Fibre Channel over Ethernet" },
    {0,                NULL                } };

diff -rBbNu wireshark-0.99.6/epan/dissectors/packet-ieee8021ag.c wireshark-0.99.6.new/epan/dissectors/packet-ieee8021ag.c
--- wireshark-0.99.6/epan/dissectors/packet-ieee8021ag.c    2007-12-18 11:43:43.000000000 +0200
+++ wireshark-0.99.6.new/epan/dissectors/packet-ieee8021ag.c     2007-12-18 11:40:10.000000000 +0200
@@ -1,5 +1,8 @@
/* packet-ieee8021ag.h
  * Routines for IEEE 802.1ag dissection
+ *
+ * Copyright (C) 2007 Alex Rizin, MRV, <arozin dot mrv com>
+ *
  * Copyright 2007 _FF_
  * Francesco Fondelli <francesco dot fondelli, gmail dot com>
  *
@@ -57,7 +60,15 @@

#define IEEE8021AG_MAID_LEN 48

-static const guint32 flags_offset = 2;
+#define CFM_CCM_FLAGS_RDI_MASK      0x80
+#define CFM_CCM_FLAGS_RES_MASK      0x78
+#define CFM_CCM_FLAGS_INTERVAL_MASK 0x07
+
+#define CFM_LTM_USE_FDB_ONLY_MASK  0x80
+#define CFM_LTM_RES_MASK            0x7f
+#define CFM_LTR_FWD_YES_MASK        0x40
+#define CFM_LTR_TERM_MEP_MASK      0x20
+#define CFM_LTR_RES_MASK            0x1f
static const guint32 flags_size = 1;
static const guint32 ftlvo_offset = 3;
static const guint32 ftlvo_size = 1;
@@ -83,6 +94,19 @@
static int hf_ieee8021ag_ccm_txfcf = -1;
static int hf_ieee8021ag_ccm_rxfcb = -1;
static int hf_ieee8021ag_ccm_txfcb = -1;
+static int hf_ieee8021ag_ltm_trn_num = -1;
+static int hf_ieee8021ag_ltm_ttl = -1;
+static int hf_ieee8021ag_ltm_use_fdb_only = -1;
+static int hf_ieee8021ag_fwd_yes = -1;
+static int hf_ieee8021ag_term = -1;
+static int hf_ieee8021ag_ltr_res = -1;
+static int hf_ieee8021ag_ltr_relay = -1;
+static int hf_ieee8021ag_ltm_res = -1;
+static int hf_ieee8021ag_tlv_type = -1;
+static int hf_ieee8021ag_tlv_len = -1;
+static int hf_ieee8021ag_tlv_value = -1;
+static int hf_ieee8021ag_tlv_port_status = -1;
+static int hf_ieee8021ag_tlv_if_status = -1;
static int hf_ieee8021ag_ccm_endtlv = -1;

/* maid fields */
@@ -99,7 +123,16 @@
/* subtree pointers */
static gint ett_ieee8021ag = -1;
static gint ett_ieee8021ag_ccm = -1;
+static gint ett_ieee8021ag_ltm = -1;
+static gint ett_ieee8021ag_ltr = -1;
+static gint ett_ieee8021ag_lbm = -1;
+static gint ett_ieee8021ag_lbr = -1;
+static gint ett_ieee8021ag_dmr = -1;
+static gint ett_ieee8021ag_dmm = -1;
static gint ett_ieee8021ag_maid = -1;
+static gint ett_ieee8021ag_tlv = -1;
+static gint ett_ieee8021ag_time = -1;
+static gint ett_ieee8021ag_flag = -1;

/* IEEE802.1ag/Y.1731, OpCode values */
static const range_string op_code_long_rvals[] = {
@@ -205,6 +238,42 @@
    {  0,  0, NULL                                          }
};

+static const value_string ieee8021ag_ltr_relay_names[] = {
+  { 1, "RlyHit" },
+  { 2, "RlyFDB" },
+  { 3, "RlyMPDP"},
+};
+
+// find tlv_type
+//
+typedef enum {
+  eee8021ag_end_tlv = 0,
+  eee8021ag_sender_id_tlv,
+  eee8021ag_port_status_tlv,
+  eee8021ag_data_tlv,
+  eee8021ag_interface_status_tlv,
+  eee8021ag_reply_ingress_id_tlv,
+  eee8021ag_reply_egress_id_tlv,
+  eee8021ag_ltm_egress_id_tlv,
+  eee8021ag_ltr_egress_id_tlv,
+  eee8021ag_organization_specific_tlv = 31,
+  eee8021ag_test_tlv = 32,
+} ieee8021ag_tlv_t;
+
+static const value_string ieee8021ag_tlv_type_names[] = {
+  { eee8021ag_end_tlv,                  "End TLV" },
+  { eee8021ag_sender_id_tlv,            "SenderId TLV" },
+  { eee8021ag_port_status_tlv,          "PortStatus TLV" },
+  { eee8021ag_data_tlv,                  "Data TLV" },
+  { eee8021ag_interface_status_tlv,      "InterfaceStatus TLV" },
+  { eee8021ag_reply_ingress_id_tlv,      "ReplyIngress TLV" },
+  { eee8021ag_reply_egress_id_tlv,      "Reply Egress TLV" },
+  { eee8021ag_ltm_egress_id_tlv,        "LTM Egress TLV" },
+  { eee8021ag_ltr_egress_id_tlv,        "LTR Egress TLV" },
+  { eee8021ag_organization_specific_tlv, "Organization Specific TLV" },
+  { eee8021ag_test_tlv,                  "Test TLV" },
+};
+
/* IEEE802.1ag/Y.1731, Association Name format type */
static const range_string maid_sformat_type_rvals[] = {

@@ -222,6 +291,27 @@
    {  0,  0, NULL                                          }
};

+static const true_false_string yesno = {
+    "Yes",
+    "No"
+};
+
+static const value_string port_status_vals[] = {
+  { 0,                  "Invalid" },
+  { 1,                  "psBlocked" },
+  { 2,                  "psUp" },
+};
+
+static const value_string if_status_vals[] = {
+  { 0,                  "Invalid" },
+  { 1,                  "isUp" },
+  { 2,                  "isDown" },
+  { 3,                  "isTesting" },
+  { 4,                  "isUnknown" },
+  { 5,                  "isDormant" },
+  { 6,                  "isNotPresent" },
+  { 7,                  "isLowerLayerDown" },
+};

static void
dissect_maid(tvbuff_t *tvb, guint32 offset, packet_info *pinfo _U_, proto_tree *tree)
@@ -350,64 +440,110 @@
    offset += pad_size;
}

-static void
-dissect_ccm(tvbuff_t *tvb, guint32 offset, packet_info *pinfo _U_, proto_tree *tree)
+static void dissect_tlv (proto_tree *tree, tvbuff_t *tvb, guint32 *offset)
{
-    guint8 rdi = 0;
-    guint8 res1 = 0;
-    guint32 res2 = 0;
-    guint8 interval = 0;
-    guint8 ftlvo = 0;
-    guint32 seq_num = 0;
-    guint16 mepid = 0;
-    guint8 endtlv = 0;
+  guint8  tlv_type = 0;
+  guint16 tlv_length = 0;
+  guint8  t8 = 0;
    proto_item *ti = NULL;
-    proto_tree *ccm_tree = NULL;
+  proto_tree *subtree = NULL;

-    /* create ccm subtree */
-    ti = proto_tree_add_text(tree, tvb, offset, -1, "CCM");
-    ccm_tree = proto_item_add_subtree(ti, ett_ieee8021ag_ccm);
+  for (;;) {
+    if (! tvb_bytes_exist(tvb, *offset, 1)) {
+      proto_tree_add_boolean_hidden(tree, hf_ieee8021ag_malformed, tvb, *offset, 0, TRUE);
+      proto_tree_add_text(tree, tvb, *offset, -1, "Error: Packet does not have End TLV");
+      return;
+    }
+    tlv_type = tvb_get_guint8(tvb, *offset);
+    if (! tlv_type)  {
+      proto_tree_add_uint(tree, hf_ieee8021ag_tlv_type, tvb, *offset, 1, tlv_type);
+      *offset += 1;
+      return; /* End TLV */
+    }
+    *offset += 1;
+    tlv_length = tvb_get_ntohs(tvb, *offset);
+    ti = proto_tree_add_text(tree, tvb, *offset, tlv_length, match_strval(tlv_type, ieee8021ag_tlv_type_names));
+    subtree = proto_item_add_subtree(ti, ett_ieee8021ag_tlv);
+    proto_tree_add_uint(subtree, hf_ieee8021ag_tlv_type, tvb, *offset - 1, 1, tlv_type);
+    proto_tree_add_uint(subtree, hf_ieee8021ag_tlv_len, tvb, *offset, 2, tlv_length);
+    *offset += 2;
+    switch (tlv_type) {
+      case eee8021ag_sender_id_tlv:
+        proto_tree_add_item(subtree, hf_ieee8021ag_tlv_value, tvb, *offset, tlv_length, FALSE);
+        break;
+      case eee8021ag_port_status_tlv:
+        t8 = tvb_get_guint8(tvb, *offset);
+        proto_tree_add_uint(subtree, hf_ieee8021ag_tlv_port_status, tvb, *offset, 1, t8);
+        break;
+      case eee8021ag_data_tlv:
+        proto_tree_add_item(subtree, hf_ieee8021ag_tlv_value, tvb, *offset, tlv_length, FALSE);
+        break;
+      case eee8021ag_interface_status_tlv:
+        t8 = tvb_get_guint8(tvb, *offset);
+        proto_tree_add_uint(subtree, hf_ieee8021ag_tlv_if_status, tvb, *offset, 1, t8);
+        break;
+      case eee8021ag_reply_ingress_id_tlv:
+        proto_tree_add_item(subtree, hf_ieee8021ag_tlv_value, tvb, *offset, tlv_length, FALSE);
+        break;
+      case eee8021ag_reply_egress_id_tlv:
+        proto_tree_add_item(subtree, hf_ieee8021ag_tlv_value, tvb, *offset, tlv_length, FALSE);
+        break;
+      case eee8021ag_ltm_egress_id_tlv:
+        proto_tree_add_item(subtree, hf_ieee8021ag_tlv_value, tvb, *offset, tlv_length, FALSE);
+        break;
+      case eee8021ag_ltr_egress_id_tlv:
+        proto_tree_add_item(subtree, hf_ieee8021ag_tlv_value, tvb, *offset, tlv_length, FALSE);
+        break;
+      case eee8021ag_organization_specific_tlv:
+        proto_tree_add_item(subtree, hf_ieee8021ag_tlv_value, tvb, *offset, tlv_length, FALSE);
+        break;
+      case eee8021ag_test_tlv:
+        proto_tree_add_item(subtree, hf_ieee8021ag_tlv_value, tvb, *offset, tlv_length, FALSE);
+        break;
+      default:
+        proto_tree_add_item(subtree, hf_ieee8021ag_tlv_value, tvb, *offset, tlv_length, FALSE);
+        break;

-    /* reinterpret flags field in ccm case */
-    rdi = tvb_get_guint8(tvb, flags_offset) & 0x80;
-    proto_tree_add_boolean(ccm_tree, hf_ieee8021ag_ccm_rdi,
-                  tvb, flags_offset, flags_size, rdi);
-
-    res1 = tvb_get_guint8(tvb, flags_offset) & 0x78;
-    proto_tree_add_uint_hidden(ccm_tree, hf_ieee8021ag_ccm_res1,
-                  tvb, flags_offset, flags_size, res1);
-    if (res1 != 0) {
-        proto_tree_add_boolean_hidden(tree, hf_ieee8021ag_malformed,
-                          tvb, flags_offset, flags_size, TRUE);
-        proto_tree_add_text(ccm_tree, tvb, flags_offset, flags_size,
-                    "Error: bit 7, 6, 5 and 4 of "
-                    "Flags field should be zero");
    }
+    *offset += tlv_length;
+  }
+}
   
-    interval = tvb_get_guint8(tvb, flags_offset) & 0x07;
-    proto_tree_add_item(ccm_tree, hf_ieee8021ag_ccm_interval,
-                tvb, flags_offset, flags_size, interval);
+static void check_specific_ftlvo (tvbuff_t *tvb, guint32 offset, proto_tree *tree, guint8 must_by_ftlvo)
+{
+  guint8 ftlvo;

    /* check first tlv offset field */
    ftlvo = tvb_get_guint8(tvb, ftlvo_offset);
-    if (ftlvo < 70) {
-        proto_tree_add_boolean_hidden(tree, hf_ieee8021ag_malformed,
-                      tvb, ftlvo_offset, ftlvo_size, TRUE);
-        proto_tree_add_text(ccm_tree, tvb, ftlvo_offset, ftlvo_size,
-                "Error: First TLV Offset field "
-                "should be >= 70");
-    }

    /* check advertised size agaist real pkt size */
    if (!tvb_bytes_exist(tvb, offset, ftlvo + 1)) {
-
-        proto_tree_add_boolean_hidden(tree, hf_ieee8021ag_malformed,
-                      tvb, offset, 0, TRUE);
-        proto_tree_add_text(ccm_tree, tvb, offset, -1,
-                "Error: Packet too short");
+    proto_tree_add_boolean_hidden(tree, hf_ieee8021ag_malformed, tvb, offset, 0, TRUE);
+    proto_tree_add_text(tree, tvb, offset, -1, "Error: Packet too short");
        THROW(ReportedBoundsError);
        }

+  if (ftlvo < must_by_ftlvo) {
+    proto_tree_add_boolean_hidden(tree, hf_ieee8021ag_malformed, tvb, ftlvo_offset, ftlvo_size, TRUE);
+    proto_tree_add_text(tree, tvb, ftlvo_offset, ftlvo_size, "Error: First TLV Offset field should be >= %d", (int) must_by_ftlvo);
+  }
+}
+
+static void
+dissect_ccm(tvbuff_t *tvb, guint32 offset, packet_info *pinfo _U_, proto_tree *tree)
+{
+    guint32 res2 = 0;
+    guint32 seq_num = 0;
+    guint16 mepid = 0;
+    proto_item *ti = NULL;
+    proto_tree *ccm_tree = NULL;
+
+    /* create ccm subtree */
+    ti = proto_tree_add_text(tree, tvb, offset, -1, "CCM");
+    ccm_tree = proto_item_add_subtree(ti, ett_ieee8021ag_ccm);
+
+    check_specific_ftlvo (tvb, offset, ccm_tree, 70);
+
    /* and finally others ccm fields */
    seq_num = tvb_get_ntohl(tvb, offset);
    proto_tree_add_uint(ccm_tree, hf_ieee8021ag_ccm_seq_num,
@@ -463,26 +599,74 @@
    *  d) Organization-Specific TLV (21.5.2).
    */

-    /* there must be only one more byte: the stop byte (End TLV) */
-    endtlv = tvb_get_guint8(tvb, offset);
-    proto_tree_add_item(ccm_tree, hf_ieee8021ag_ccm_endtlv,
-                tvb, offset, 1, FALSE);
-    if (endtlv != 0) {
-        proto_tree_add_boolean_hidden(tree, hf_ieee8021ag_malformed,
-                          tvb, offset, 1, TRUE);
-        proto_tree_add_text(ccm_tree, tvb, offset, 1,
-                    "Error: End TLV octect "
-                    "should be set to zero");
+    dissect_tlv (ccm_tree, tvb, &offset);
+
+    /* extra check: no more data should be present */
+    if (tvb_bytes_exist(tvb, offset, 1)) {
+      proto_tree_add_text(tree, tvb, offset, -1, "Padding");
    }
-    offset += 1;
+}
+
+static void dissect_timestamp (tvbuff_t *tvb, guint32 *offset, proto_tree *tree, const char * stamp_name)
+{
+  proto_item *ti = NULL;
+  proto_tree *subtree = NULL;

+  ti = proto_tree_add_text(tree, tvb, *offset, 8, stamp_name);
+  subtree = proto_item_add_subtree(ti, ett_ieee8021ag_time);
+  proto_tree_add_text(subtree, tvb, *offset, 4, "tv_sec:  %lu sec.", (unsigned long) tvb_get_letohl(tvb, *offset));
+  *offset += 4;
+  proto_tree_add_text(subtree, tvb, *offset, 4, "tv_usec: %lu nanosec.", (unsigned long) tvb_get_letohl(tvb, *offset));
+  *offset += 4;
+}
+
+static void
+dissect_dmr(tvbuff_t *tvb, guint32 offset, packet_info *pinfo _U_, proto_tree *tree)
+{
+  proto_item *ti = NULL;
+  proto_tree *dmr_tree = NULL;
+
+  /* create ccm subtree */
+  ti = proto_tree_add_text(tree, tvb, offset, -1, "DMR");
+  dmr_tree = proto_item_add_subtree(ti, ett_ieee8021ag_dmr);
+
+  check_specific_ftlvo (tvb, offset, dmr_tree, 32);
+
+  dissect_timestamp (tvb, &offset, dmr_tree, "T1");
+  dissect_timestamp (tvb, &offset, dmr_tree, "T2");
+  dissect_timestamp (tvb, &offset, dmr_tree, "T3");
+  dissect_timestamp (tvb, &offset, dmr_tree, "T4");
+
+  dissect_tlv (dmr_tree, tvb, &offset);

    /* extra check: no more data should be present */
    if (tvb_bytes_exist(tvb, offset, 1)) {
+    proto_tree_add_text(tree, tvb, offset, -1, "Padding");
+  }
+}
       
-        proto_tree_add_boolean_hidden(tree, hf_ieee8021ag_malformed,
-                      tvb, offset, 0, TRUE);
-        proto_tree_add_text(ccm_tree, tvb, offset, -1,
-                "Error: Packet too long");
+static void
+dissect_dmm(tvbuff_t *tvb, guint32 offset, packet_info *pinfo _U_, proto_tree *tree)
+{
+  proto_item *ti = NULL;
+  proto_tree *dmm_tree = NULL;
+
+  /* create ccm subtree */
+  ti = proto_tree_add_text(tree, tvb, offset, -1, "DMM");
+  dmm_tree = proto_item_add_subtree(ti, ett_ieee8021ag_dmm);
+
+  check_specific_ftlvo (tvb, offset, dmm_tree, 32);
+
+  dissect_timestamp (tvb, &offset, dmm_tree, "T1");
+  dissect_timestamp (tvb, &offset, dmm_tree, "T2");
+  dissect_timestamp (tvb, &offset, dmm_tree, "T3");
+  dissect_timestamp (tvb, &offset, dmm_tree, "T4");
+
+  dissect_tlv (dmm_tree, tvb, &offset);
+
+  /* extra check: no more data should be present */
+  if (tvb_bytes_exist(tvb, offset, 1)) {
+    proto_tree_add_text(tree, tvb, offset, -1, "Padding");
        }
}

@@ -489,28 +674,164 @@
static void
dissect_lbr(tvbuff_t *tvb, guint32 offset, packet_info *pinfo _U_, proto_tree *tree)
{
-    assert(tvb); assert(offset); assert(pinfo); assert(tree); //temp
+  proto_item *ti = NULL;
+  proto_tree *lbr_tree = NULL;
+  guint32 seq_num = 0;
+
+  /* create ccm subtree */
+  ti = proto_tree_add_text(tree, tvb, offset, -1, "LBR");
+  lbr_tree = proto_item_add_subtree(ti, ett_ieee8021ag_lbr);
+
+  check_specific_ftlvo (tvb, offset, lbr_tree, 4);
+
+  seq_num = tvb_get_ntohl(tvb, offset);
+  proto_tree_add_uint(lbr_tree, hf_ieee8021ag_ccm_seq_num, tvb, offset, 4, seq_num);
+  offset += 4;
+
+  dissect_tlv (lbr_tree, tvb, &offset);
+
+  /* extra check: no more data should be present */
+  if (tvb_bytes_exist(tvb, offset, 1)) {
+    proto_tree_add_text(tree, tvb, offset, -1, "Padding");
+  }
}

static void
dissect_lbm(tvbuff_t *tvb, guint32 offset, packet_info *pinfo _U_, proto_tree *tree)
{
-    assert(tvb); assert(offset); assert(pinfo); assert(tree); //temp
+  proto_item *ti = NULL;
+  proto_tree *lbm_tree = NULL;
+  guint32 seq_num = 0;
+
+  /* create ccm subtree */
+  ti = proto_tree_add_text(tree, tvb, offset, -1, "LBM");
+  lbm_tree = proto_item_add_subtree(ti, ett_ieee8021ag_lbm);
+
+  check_specific_ftlvo (tvb, offset, lbm_tree, 4);
+
+  seq_num = tvb_get_ntohl(tvb, offset);
+  proto_tree_add_uint(lbm_tree, hf_ieee8021ag_ccm_seq_num, tvb, offset, 4, seq_num);
+  offset += 4;
+
+  dissect_tlv (lbm_tree, tvb, &offset);
+
+  /* extra check: no more data should be present */
+  if (tvb_bytes_exist(tvb, offset, 1)) {
+    proto_tree_add_text(tree, tvb, offset, -1, "Padding");
+  }
}

static void
dissect_ltr(tvbuff_t *tvb, guint32 offset, packet_info *pinfo _U_, proto_tree *tree)
{
-    assert(tvb); assert(offset); assert(pinfo); assert(tree); //temp
-}
+  guint8 t8 = 0;
+  guint32 seq_num = 0;
+  proto_item *ti = NULL;
+  proto_tree *ltr_tree = NULL;
+
+  /* create ccm subtree */
+  ti = proto_tree_add_text(tree, tvb, offset, -1, "LTR");
+  ltr_tree = proto_item_add_subtree(ti, ett_ieee8021ag_ltr);
+
+  check_specific_ftlvo (tvb, offset, ltr_tree, 6);
+
+  seq_num = tvb_get_ntohl(tvb, offset);
+  proto_tree_add_uint(ltr_tree, hf_ieee8021ag_ltm_trn_num, tvb, offset, 4, seq_num);
+  offset += 4;
+
+  t8 = tvb_get_guint8(tvb, offset);
+  proto_tree_add_uint(ltr_tree, hf_ieee8021ag_ltm_ttl, tvb, offset, 1, t8);
+  offset += 1;
+
+  t8 = tvb_get_guint8(tvb, offset);
+  proto_tree_add_uint(ltr_tree, hf_ieee8021ag_ltr_relay, tvb, offset, 1, t8);
+  offset += 1;
+
+  dissect_tlv (ltr_tree, tvb, &offset);

+  /* extra check: no more data should be present */
+  if (tvb_bytes_exist(tvb, offset, 1)) {
+    proto_tree_add_text(tree, tvb, offset, -1, "Padding");
+  }
+} /* ltr end */

static void
dissect_ltm(tvbuff_t *tvb, guint32 offset, packet_info *pinfo _U_, proto_tree *tree)
{
-    assert(tvb); assert(offset); assert(pinfo); assert(tree); //temp
+  guint8 ttl = 0;
+  guint32 seq_num = 0;
+  proto_item *ti = NULL;
+  proto_tree *ltm_tree = NULL;
+  const guint8  *mac_addr;
+  gchar  *mac_addr_str;
+
+  /* create ccm subtree */
+  ti = proto_tree_add_text(tree, tvb, offset, -1, "LTM");
+  ltm_tree = proto_item_add_subtree(ti, ett_ieee8021ag_ltm);
+
+  check_specific_ftlvo (tvb, offset, ltm_tree, 17);
+
+  seq_num = tvb_get_ntohl(tvb, offset);
+  proto_tree_add_uint(ltm_tree, hf_ieee8021ag_ltm_trn_num, tvb, offset, 4, seq_num);
+  offset += 4;
+
+  ttl = tvb_get_guint8(tvb, offset);
+  proto_tree_add_uint(ltm_tree, hf_ieee8021ag_ltm_ttl, tvb, offset, 1, ttl);
+  offset += 1;
+
+  mac_addr = tvb_get_ptr(tvb, offset, 6);
+  mac_addr_str = ether_to_str(mac_addr);
+  proto_tree_add_text(ltm_tree, tvb, offset, 6, "Original MAC Address %s", mac_addr_str);
+  offset += 6;
+
+  mac_addr = tvb_get_ptr(tvb, offset, 6);
+  mac_addr_str = ether_to_str(mac_addr);
+  proto_tree_add_text(ltm_tree, tvb, offset, 6, "Target MAC Address %s", mac_addr_str);
+  offset += 6;
+
+  dissect_tlv (ltm_tree, tvb, &offset);

+  /* extra check: no more data should be present */
+  if (tvb_bytes_exist(tvb, offset, 1)) {
+    proto_tree_add_text(tree, tvb, offset, -1, "Padding");
+  }
}


+static void dissect_flags (tvbuff_t *tvb, proto_tree *ieee8021ag_tree, guint8 opcode, guint32 offset)
+{
+  proto_item *ti = NULL;
+  proto_tree *subtree = NULL;
+  guint8 flags = 0;
+
+  flags = tvb_get_guint8(tvb, offset);
+  ti = proto_tree_add_item(ieee8021ag_tree, hf_ieee8021ag_flags, tvb, offset, 1, FALSE);
+  subtree = proto_item_add_subtree(ti, ett_ieee8021ag_flag);
+  switch (opcode) {
+    case 1:
+      proto_tree_add_boolean(subtree, hf_ieee8021ag_ccm_rdi, tvb, offset, 1, flags);
+      proto_tree_add_uint(subtree, hf_ieee8021ag_ccm_res1, tvb, offset, 1, flags);
+      proto_tree_add_uint(subtree, hf_ieee8021ag_ccm_interval, tvb, offset, 1, flags);
+      break;
+    case 2: /* lbr */
+      break;
+    case 3: /* lbr */
+      break;
+    case 4: /* ltr */
+      proto_tree_add_boolean(subtree, hf_ieee8021ag_ltm_use_fdb_only, tvb, offset, 1, flags);
+      proto_tree_add_boolean(subtree, hf_ieee8021ag_fwd_yes, tvb, offset, 1,          flags);
+      proto_tree_add_boolean(subtree, hf_ieee8021ag_term, tvb, offset, 1,            flags);
+      proto_tree_add_uint(subtree, hf_ieee8021ag_ltr_res, tvb, offset, 1,            flags);
+      break;
+    case 5: /* ltm */
+      proto_tree_add_boolean(subtree, hf_ieee8021ag_ltm_use_fdb_only, tvb, offset, 1, flags);
+      proto_tree_add_uint(subtree, hf_ieee8021ag_ltm_res, tvb, offset, 1,            flags);
+      break;
+    default:
+      break;
+  }
+}
+
static void
dissect_ieee8021ag(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
@@ -522,6 +843,7 @@

    /* get at least a full message header */
    if (!tvb_bytes_exist(tvb, 0, IEEE8021AG_HDR_LEN_MIN)) {
+        printf ("%s(%d) - %s\n", __FILE__, __LINE__, __FUNCTION__);
        if (tree) {
            proto_tree_add_boolean_hidden(tree, hf_ieee8021ag_malformed,
                              tvb, offset, 0, TRUE);
@@ -550,6 +872,7 @@

    if (!tree) {
        /* nothing to do, col info and proto info already done */
+        printf ("%s(%d) - %s\n", __FILE__, __LINE__, __FUNCTION__);
        return;
    }

@@ -571,8 +894,11 @@
    opcode = tvb_get_guint8(tvb, offset);
    proto_tree_add_item(ieee8021ag_tree, hf_ieee8021ag_op_code,
                tvb, offset, 1, FALSE);
-    offset += 1;

+    offset += 1;
+#if 1
+    dissect_flags (tvb, ieee8021ag_tree, opcode, offset);
+#else
    /*
    * FF: The rest is opCode specific. Please note that "Flags" field is
    * hemmm "a placeholder where you can put whatever you want with
@@ -583,6 +909,7 @@
    */
    proto_tree_add_item(ieee8021ag_tree, hf_ieee8021ag_flags,
                tvb, offset, 1, FALSE);
+#endif
    offset += 1;

    proto_tree_add_item(ieee8021ag_tree, hf_ieee8021ag_ftlv_offset,
@@ -605,6 +933,12 @@
    case 5:
        return dissect_ltm(tvb, offset, pinfo, ieee8021ag_tree);
        break;
+    case 46:
+        return dissect_dmr(tvb, offset, pinfo, ieee8021ag_tree);
+        break;
+    case 47:
+        return dissect_dmm(tvb, offset, pinfo, ieee8021ag_tree);
+        break;
    default:
        /* reserved pdu type, I can't do much */
        if (tvb_bytes_exist(tvb, offset, 1)) {
@@ -680,7 +1014,7 @@
          {
              "Interval",
              "ieee8021ag.ccm.interval",
-              FT_UINT8, BASE_DEC, VALS(&ccm_interval_vals), 0x0,
+              FT_UINT8, BASE_DEC, VALS(&ccm_interval_vals), CFM_CCM_FLAGS_INTERVAL_MASK,
              "The CCM transmission interval",
              HFILL
          }
@@ -709,7 +1043,8 @@
          {
              "RDI",
              "ieee8021ag.ccm.rdi",
-              FT_BOOLEAN, BASE_DEC, NULL, 0x0,
+              FT_BOOLEAN, 8, TFS(&yesno),
+              CFM_CCM_FLAGS_RDI_MASK,
              "Whether the defect indication is communicated "
              "by the transmitting MEP",
              HFILL
@@ -715,15 +1050,15 @@
              HFILL
          }
        },
+
        { &hf_ieee8021ag_ccm_res1,
-          {
-              "reserved",
-              "ieee8021ag.ccm.res1",
-              FT_UINT8, BASE_DEC, NULL, 0x0,
-              "",
-              HFILL
+          { "reserved", "ieee8021ag.ccm.res1",
+            FT_UINT8, BASE_DEC, NULL,
+            CFM_CCM_FLAGS_RES_MASK,
+            "", HFILL
          }
        },
+
        { &hf_ieee8021ag_ccm_res2,
          {
              "reserved",
@@ -773,6 +1108,120 @@
              HFILL
          }
        },
+
+        { &hf_ieee8021ag_ltr_res,
+          { "reserved", "ieee8021ag.ccm.res1",
+            FT_UINT8, BASE_DEC, NULL, CFM_LTR_RES_MASK,
+            "", HFILL
+          }
+        },
+
+        { &hf_ieee8021ag_ltm_trn_num,
+          {
+              "Transaction Number",
+              "ieee8021ag.ltm.trn_num",
+              FT_UINT32, BASE_DEC, NULL, 0x0,
+              "A MEP copies the contents of the nextLTMtransID variable (20.36.1) to this field",
+              HFILL
+          }
+        },
+        { &hf_ieee8021ag_ltm_ttl,
+          {
+              "TTL",
+              "ieee8021ag.ltm.ttl",
+              FT_UINT8, BASE_DEC, NULL, 0x0,
+              "TTL - time to live counter",
+              HFILL
+          }
+        },
+        { &hf_ieee8021ag_ltm_res,
+          { "reserved", "ieee8021ag.ccm.res1",
+            FT_UINT8, BASE_DEC, NULL, CFM_LTM_RES_MASK,
+            "", HFILL
+          }
+        },
+
+        { &hf_ieee8021ag_ltm_use_fdb_only,
+          {
+              "useFDBonly",
+              "ieee8021ag.ltm.use_fdb_only",
+              FT_BOOLEAN, 8, TFS(&yesno), CFM_LTM_USE_FDB_ONLY_MASK,
+              "Only MAC addresses learned in a Bridge’s Filtering Database, and"
+              "not information saved in the MIP CCM Database, is to"
+              "be used to determine the Egress Port",
+              HFILL
+          }
+        },
+        { &hf_ieee8021ag_fwd_yes,
+          {
+              "FwdYes",
+              "ieee8021ag.ltm.fwd_yes",
+              FT_BOOLEAN, 8, TFS(&yesno), CFM_LTR_FWD_YES_MASK,
+              "The LTM was (1) or was not (0) forwarded",
+              HFILL
+          }
+        },
+        { &hf_ieee8021ag_term,
+          {
+              "TerminalMEP",
+              "ieee8021ag.ltm.terminal_mep",
+              FT_BOOLEAN, 8, TFS(&yesno), CFM_LTR_TERM_MEP_MASK,
+              "The MP reported in the Reply Egress TLV (Reply Ingress TLV, if"
+              "the Reply Egress TLV is not present) is a MEP",
+              HFILL
+          }
+        },
+
+        { &hf_ieee8021ag_ltr_relay,
+          {
+              "Relay Action",
+              "ieee8021ag.ltr.relay",
+              FT_UINT8, BASE_DEC, VALS(&ieee8021ag_ltr_relay_names), 0x0,
+              "Reports how the data frame targeted by the LTM would be passed through the MAC Relay Entity to"
+              "the Egress Bridge Port",
+              HFILL
+          }
+        },
+
+        { &hf_ieee8021ag_tlv_type,
+          { "Type", "ieee8021ag.tlv.type",
+            FT_UINT8, BASE_DEC, VALS(ieee8021ag_tlv_type_names), 0x0,
+            "TLV Type", HFILL
+          }
+        },
+        { &hf_ieee8021ag_tlv_len,
+          { "Length", "ieee8021ag.tlv.len",
+            FT_UINT16, BASE_DEC, NULL, 0x0, "TLV Length", HFILL
+          }
+        },
+
+        { &hf_ieee8021ag_tlv_port_status,
+          {
+              "PortStatus",
+              "ieee8021ag.tlv.port_status",
+              FT_UINT8, BASE_DEC, VALS(&port_status_vals), 0x0,
+              "Port Status TLV",
+              HFILL
+          }
+        },
+
+        { &hf_ieee8021ag_tlv_if_status,
+          {
+              "ifStatus",
+              "ieee8021ag.tlv.if_status",
+              FT_UINT8, BASE_DEC, VALS(&if_status_vals), 0x0,
+              "Interface Status TLV",
+              HFILL
+          }
+        },
+
+        { &hf_ieee8021ag_tlv_value,
+          { "Value", "ieee8021ag.tlv.value",
+            FT_BYTES, BASE_NONE, NULL, 0x0, "TLV Value", HFILL
+          }
+        },
+
+
        { &hf_ieee8021ag_ccm_endtlv,
          {
              "End TLV",
@@ -855,8 +1304,17 @@

        static gint *ett[] = {
                &ett_ieee8021ag,
+                &ett_ieee8021ag_flag,
                &ett_ieee8021ag_ccm,
-        &ett_ieee8021ag_maid
+                &ett_ieee8021ag_lbr,
+                &ett_ieee8021ag_lbm,
+                &ett_ieee8021ag_ltr,
+                &ett_ieee8021ag_ltm,
+                &ett_ieee8021ag_dmr,
+                &ett_ieee8021ag_dmm,
+                &ett_ieee8021ag_maid,
+                &ett_ieee8021ag_tlv,
+                &ett_ieee8021ag_time
        };
   
        proto_ieee8021ag = proto_register_protocol("IEEE 802.1ag Connectivity "
diff -rBbNu wireshark-0.99.6/epan/dissectors/register.c wireshark-0.99.6.new/epan/dissectors/register.c
--- wireshark-0.99.6/epan/dissectors/register.c    2007-07-05 22:29:43.000000000 +0300
+++ wireshark-0.99.6.new/epan/dissectors/register.c    2007-12-18 10:13:43.000000000 +0200
@@ -302,6 +302,7 @@
  {extern void proto_register_icq (void); if(cb) (*cb)(RA_REGISTER, "proto_register_icq", client_data); proto_register_icq ();}
  {extern void proto_register_idp (void); if(cb) (*cb)(RA_REGISTER, "proto_register_idp", client_data); proto_register_idp ();}
  {extern void proto_register_ieee80211 (void); if(cb) (*cb)(RA_REGISTER, "proto_register_ieee80211", client_data); proto_register_ieee80211 ();}
+  {extern void proto_register_ieee8021ag (void); if(cb) (*cb)(RA_REGISTER, "proto_register_ieee8021ag", client_data); proto_register_ieee8021ag ();}
  {extern void proto_register_ieee802a (void); if(cb) (*cb)(RA_REGISTER, "proto_register_ieee802a", client_data); proto_register_ieee802a ();}
  {extern void proto_register_ifcp (void); if(cb) (*cb)(RA_REGISTER, "proto_register_ifcp", client_data); proto_register_ifcp ();}
  {extern void proto_register_igap (void); if(cb) (*cb)(RA_REGISTER, "proto_register_igap", client_data); proto_register_igap ();}
@@ -1006,6 +1007,7 @@
  {extern void proto_reg_handoff_icq (void); if(cb) (*cb)(RA_HANDOFF, "proto_reg_handoff_icq", client_data); proto_reg_handoff_icq ();}
  {extern void proto_reg_handoff_idp (void); if(cb) (*cb)(RA_HANDOFF, "proto_reg_handoff_idp", client_data); proto_reg_handoff_idp ();}
  {extern void proto_reg_handoff_ieee80211 (void); if(cb) (*cb)(RA_HANDOFF, "proto_reg_handoff_ieee80211", client_data); proto_reg_handoff_ieee80211 ();}
+  {extern void proto_reg_handoff_ieee8021ag (void); if(cb) (*cb)(RA_HANDOFF, "proto_reg_handoff_ieee8021ag", client_data); proto_reg_handoff_ieee8021ag ();}
  {extern void proto_reg_handoff_ieee802_3 (void); if(cb) (*cb)(RA_HANDOFF, "proto_reg_handoff_ieee802_3", client_data); proto_reg_handoff_ieee802_3 ();}
  {extern void proto_reg_handoff_ieee802a (void); if(cb) (*cb)(RA_HANDOFF, "proto_reg_handoff_ieee802a", client_data); proto_reg_handoff_ieee802a ();}
  {extern void proto_reg_handoff_ifcp (void); if(cb) (*cb)(RA_HANDOFF, "proto_reg_handoff_ifcp", client_data); proto_reg_handoff_ifcp ();}
@@ -1412,6 +1414,6 @@

gulong register_count(void)
{
-  return 715 + 683;
+  return 716 + 684;

}
diff -rBbNu wireshark-0.99.6/epan/etypes.h wireshark-0.99.6.new/epan/etypes.h
--- wireshark-0.99.6/epan/etypes.h    2007-07-05 22:25:05.000000000 +0300
+++ wireshark-0.99.6.new/epan/etypes.h    2007-12-18 14:12:55.000000000 +0200
@@ -344,6 +344,10 @@
#define ETHERTYPE_FCOE        0x8906    /* Fibre Channel over Ethernet */
#endif

+#ifndef ETHERTYPE_IEEE_802_1AG
+#define ETHERTYPE_IEEE_802_1AG 0x89e2
+#endif
+
#ifndef ETHERTYPE_LOOP
#define ETHERTYPE_LOOP        0x9000     /* used for layer 2 testing (do i see my own frames on the wire) */
#endif



Looking for the perfect gift? Give the gift of Flickr!