From Didier Gautheron:
[obnox/wireshark/wip.git] / epan / dissectors / packet-icmpv6.c
index 52ff21915c97e339dfc9d259e9a4dfd0b7432e11..84d94346e8a086e8de05c36bd7973411ef3b11b3 100644 (file)
 # include "config.h"
 #endif
 
-#include <stdio.h>
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#include <stdlib.h>
 #include <string.h>
 
 #include <glib.h>
 
 
 #ifndef offsetof
-#define        offsetof(type, member)  ((size_t)(&((type *)0)->member))
+#define offsetof(type, member)  ((size_t)(&((type *)0)->member))
 #endif
 
 /*
  * See, under http://www.ietf.org/internet-drafts/
  *
- *     draft-ietf-mobileip-ipv6-15.txt
+ *      draft-ietf-mobileip-ipv6-15.txt
  *
  * and
  *
- *     draft-ietf-ipngwg-icmp-name-lookups-08.txt
+ *      draft-ietf-ipngwg-icmp-name-lookups-08.txt
  *
  * and
  *
- *     draft-ietf-mobileip-hmipv6-05.txt
+ *      draft-ietf-mobileip-hmipv6-05.txt
  *
  * and
  *
- *     rfc4068.txt
+ *      rfc4068.txt
  */
 
 static int proto_icmpv6 = -1;
@@ -96,6 +89,11 @@ static int hf_icmpv6_option_type = -1;
 static int hf_icmpv6_option_length = -1;
 static int hf_icmpv6_opt_cga_pad_len = -1;
 static int hf_icmpv6_opt_cga = -1;
+static int hf_icmpv6_opt_cga_modifier = -1;
+static int hf_icmpv6_opt_cga_subnet_prefix = -1;
+static int hf_icmpv6_opt_cga_count = -1;
+static int hf_icmpv6_opt_cga_ext_type = -1;
+static int hf_icmpv6_opt_cga_ext_length = -1;
 static int hf_icmpv6_opt_rsa_key_hash = -1;
 static int hf_icmpv6_opt_name_type = -1;
 static int hf_icmpv6_opt_name_x501 = -1;
@@ -108,6 +106,7 @@ static int hf_icmpv6_x509if_Name = -1;
 static int hf_icmpv6_x509af_Certificate = -1;
 static int hf_icmpv6_recursive_dns_serv = -1;
 
+
 static gint ett_icmpv6 = -1;
 static gint ett_icmpv6opt = -1;
 static gint ett_icmpv6flag = -1;
@@ -120,130 +119,202 @@ static gint ett_nodeinfo_nodebitmap = -1;
 static gint ett_nodeinfo_nodedns = -1;
 static gint ett_multicastRR = -1;
 static gint ett_icmpv6opt_name = -1;
+static gint ett_cga_param_name = -1;
 
 static dissector_handle_t ipv6_handle;
 static dissector_handle_t data_handle;
 
+static const value_string icmpv6_type_str[] = {
+    { ICMP6_DST_UNREACH,           "Unreachable" },
+    { ICMP6_PACKET_TOO_BIG,        "Too big" },
+    { ICMP6_TIME_EXCEEDED,         "Time exceeded" },
+    { ICMP6_PARAM_PROB,            "Parameter problem" },
+    { ICMP6_ECHO_REQUEST,          "Echo request" },
+    { ICMP6_ECHO_REPLY,            "Echo reply" },
+    { ICMP6_MEMBERSHIP_QUERY,      "Multicast listener query" },
+    { ICMP6_MEMBERSHIP_REPORT,     "Multicast listener report" },
+    { ICMP6_MEMBERSHIP_REDUCTION,  "Multicast listener done" },
+    { ND_ROUTER_SOLICIT,           "Router solicitation" },
+    { ND_ROUTER_ADVERT,            "Router advertisement" },
+    { ND_NEIGHBOR_SOLICIT,         "Neighbor solicitation" },
+    { ND_NEIGHBOR_ADVERT,          "Neighbor advertisement" },
+    { ND_REDIRECT,                 "Redirect" },
+    { ICMP6_ROUTER_RENUMBERING,    "Router renumbering" },
+    { ICMP6_NI_QUERY,              "Node information query" },
+    { ICMP6_NI_REPLY,              "Node information reply" },
+    { ICMP6_IND_SOLICIT,           "Inverse neighbor discovery solicitation" },
+    { ICMP6_IND_ADVERT,            "Inverse neighbor discovery advertisement" },
+    { ICMP6_MLDV2_REPORT,          "Multicast Listener Report Message v2" },
+    { ICMP6_MIP6_DHAAD_REQUEST,    "Dynamic Home Agent Address Discovery Request" },
+    { ICMP6_MIP6_DHAAD_REPLY,      "Dynamic Home Agent Address Discovery Reply" },
+    { ICMP6_MIP6_MPS,              "Mobile Prefix Solicitation" },
+    { ICMP6_MIP6_MPA,              "Mobile Prefix Advertisement" },
+    { ICMP6_CERT_PATH_SOL,         "Certification Path Solicitation" },
+    { ICMP6_CERT_PATH_AD,          "Certification Path Advertisement" },
+    { ICMP6_EXPERIMENTAL_MOBILITY, "Experimental Mobility" },
+    { ICMP6_MCAST_ROUTER_ADVERT,   "Multicast Router Advertisement" },
+    { ICMP6_MCAST_ROUTER_SOLICIT,  "Multicast Router Solicitation" },
+    { ICMP6_MCAST_ROUTER_TERM,     "Multicast Router Termination" },
+    { ICMP6_FMIPV6_MESSAGES,       "FMIPv6 Messages" },
+    { 0, NULL }
+};
+
+static const value_string icmpv6_unreach_code_str[] = {
+    { ICMP6_DST_UNREACH_NOROUTE,     "Route unreachable" },
+    { ICMP6_DST_UNREACH_ADMIN,       "Administratively prohibited" },
+    { ICMP6_DST_UNREACH_NOTNEIGHBOR, "Not a neighbor" },
+    { ICMP6_DST_UNREACH_ADDR,        "Address unreachable" },
+    { ICMP6_DST_UNREACH_NOPORT,      "Port unreachable" },
+    { 0, NULL }
+};
+
+static const value_string icmpv6_timeex_code_str[] = {
+    { ICMP6_TIME_EXCEED_TRANSIT,    "In-transit" },
+    { ICMP6_TIME_EXCEED_REASSEMBLY, "Reassembly" },
+    { 0, NULL }
+};
+
+static const value_string icmpv6_paramprob_code_str[] = {
+    { ICMP6_PARAMPROB_HEADER,     "Header" },
+    { ICMP6_PARAMPROB_NEXTHEADER, "Next header" },
+    { ICMP6_PARAMPROB_OPTION,     "Option" },
+    { 0, NULL }
+};
+
+static const value_string icmpv6_router_renum_code_str[] = {
+    { ICMP6_ROUTER_RENUMBERING_COMMAND,      "Command" },
+    { ICMP6_ROUTER_RENUMBERING_RESULT,       "Result" },
+    { ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET, "Sequence number reset" },
+    { 0, NULL }
+};
+
 static const value_string names_nodeinfo_qtype[] = {
-    { NI_QTYPE_NOOP,           "NOOP" },
-    { NI_QTYPE_SUPTYPES,       "Supported query types" },
-    { NI_QTYPE_DNSNAME,                "DNS name" },
-    { NI_QTYPE_NODEADDR,       "Node addresses" },
-    { NI_QTYPE_IPV4ADDR,       "IPv4 node addresses" },
-    { 0,                       NULL }
+    { NI_QTYPE_NOOP,            "NOOP" },
+    { NI_QTYPE_SUPTYPES,        "Supported query types" },
+    { NI_QTYPE_DNSNAME,         "DNS name" },
+    { NI_QTYPE_NODEADDR,        "Node addresses" },
+    { NI_QTYPE_IPV4ADDR,        "IPv4 node addresses" },
+    { 0,                        NULL }
 };
 
 static const value_string names_rrenum_matchcode[] = {
-    { RPM_PCO_ADD,             "Add" },
-    { RPM_PCO_CHANGE,          "Change" },
-    { RPM_PCO_SETGLOBAL,       "Set Global" },
-    { 0,                       NULL }
+    { RPM_PCO_ADD,              "Add" },
+    { RPM_PCO_CHANGE,           "Change" },
+    { RPM_PCO_SETGLOBAL,        "Set Global" },
+    { 0,                        NULL }
 };
 
 static const value_string names_router_pref[] = {
-        { ND_RA_FLAG_RTPREF_HIGH,      "High" },
-        { ND_RA_FLAG_RTPREF_MEDIUM,    "Medium" },
-        { ND_RA_FLAG_RTPREF_LOW,       "Low" },
-        { ND_RA_FLAG_RTPREF_RSV,       "Reserved" },
-       { 0, NULL}
+    { ND_RA_FLAG_RTPREF_HIGH,   "High" },
+    { ND_RA_FLAG_RTPREF_MEDIUM, "Medium" },
+    { ND_RA_FLAG_RTPREF_LOW,    "Low" },
+    { ND_RA_FLAG_RTPREF_RSV,    "Reserved" },
+    { 0, NULL}
 };
 
 static const value_string names_fmip6_prrtadv_code[] = {
-       { FMIP6_PRRTADV_MNTUP,  "MN should use AP-ID, AR-info tuple" },
-       { FMIP6_PRRTADV_NI_HOVER,       "Network Initiated Handover trigger" },
-       { FMIP6_PRRTADV_NORTINFO,       "No new router information" },
-       { FMIP6_PRRTADV_LIMRTINFO,      "Limited new router information" },
-       { FMIP6_PRRTADV_UNSOL,  "Unsolicited" },
-       { 0,                    NULL }
+    { FMIP6_PRRTADV_MNTUP,      "MN should use AP-ID, AR-info tuple" },
+    { FMIP6_PRRTADV_NI_HOVER,   "Network Initiated Handover trigger" },
+    { FMIP6_PRRTADV_NORTINFO,   "No new router information" },
+    { FMIP6_PRRTADV_LIMRTINFO,  "Limited new router information" },
+    { FMIP6_PRRTADV_UNSOL,      "Unsolicited" },
+    { 0,                        NULL }
 };
 
 static const value_string names_fmip6_hi_code[] = {
-       { FMIP6_HI_PCOA,        "FBU sent from previous link" },
-       { FMIP6_HI_NOTPCOA,     "FBU sent from new link" },
-       { 0,                    NULL }
+    { FMIP6_HI_PCOA,    "FBU sent from previous link" },
+    { FMIP6_HI_NOTPCOA, "FBU sent from new link" },
+    { 0,                NULL }
 };
 
 static const value_string names_fmip6_hack_code[] = {
-       { FMIP6_HACK_VALID,     "Handover Accepted, NCoA valid" },
-       { FMIP6_HACK_INVALID,   "Handover Accepted, NCoA not valid" },
-       { FMIP6_HACK_INUSE,     "Handover Accepted, NCoA in use" },
-       { FMIP6_HACK_ASSIGNED,  "Handover Accepted, NCoA assigned" },
-       { FMIP6_HACK_NOTASSIGNED,       "Handover Accepted, NCoA not assigned" },
-       { FMIP6_HACK_NOTACCEPTED,       "Handover Not Accepted, reason unspecified" },
-       { FMIP6_HACK_PROHIBITED,        "Administratively prohibited" },
-       { FMIP6_HACK_INSUFFICIENT,      "Insufficient resources" },
-       { 0,                    NULL }
+    { FMIP6_HACK_VALID,         "Handover Accepted, NCoA valid" },
+    { FMIP6_HACK_INVALID,       "Handover Accepted, NCoA not valid" },
+    { FMIP6_HACK_INUSE,         "Handover Accepted, NCoA in use" },
+    { FMIP6_HACK_ASSIGNED,      "Handover Accepted, NCoA assigned" },
+    { FMIP6_HACK_NOTASSIGNED,   "Handover Accepted, NCoA not assigned" },
+    { FMIP6_HACK_NOTACCEPTED,   "Handover Not Accepted, reason unspecified" },
+    { FMIP6_HACK_PROHIBITED,    "Administratively prohibited" },
+    { FMIP6_HACK_INSUFFICIENT,  "Insufficient resources" },
+    { 0,                        NULL }
 };
 
 static const value_string names_fmip6_ip_addr_opt_code[] = {
-       { FMIP6_OPT_IP_ADDRESS_OPTCODE_PCOA,    "Old Care-of Address" },
-       { FMIP6_OPT_IP_ADDRESS_OPTCODE_NCOA,    "New Care-of Address" },
-       { FMIP6_OPT_IP_ADDRESS_OPTCODE_NAR,     "NAR's IP address" },
-       { 0,                    NULL }
+    { FMIP6_OPT_IP_ADDRESS_OPTCODE_PCOA, "Old Care-of Address" },
+    { FMIP6_OPT_IP_ADDRESS_OPTCODE_NCOA, "New Care-of Address" },
+    { FMIP6_OPT_IP_ADDRESS_OPTCODE_NAR,  "NAR's IP address" },
+    { 0,                        NULL }
 };
 
 static const value_string names_fmip6_lla_opt_code[] = {
-       { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_WILDCARD,        "Wildcard" },
-       { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_NAP,     "Link-layer Address of the New Access Point" },
-       { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_MN,      "Link-layer Address of the MN" },
-       { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_NAR,     "Link-layer Address of the NAR" },
-       { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_SRC,     "Link-layer Address of the source" },
-       { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_CURROUTER,       "The AP belongs to the current interface of the router" },
-       { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_NOPREFIX,        "No prefix information available" },
-       { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_NOSUPPORT,       "No fast handovers support available" },
-       { 0,                    NULL }
+    { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_WILDCARD,  "Wildcard" },
+    { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_NAP,       "Link-layer Address of the New Access Point" },
+    { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_MN,        "Link-layer Address of the MN" },
+    { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_NAR,       "Link-layer Address of the NAR" },
+    { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_SRC,       "Link-layer Address of the source" },
+    { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_CURROUTER, "The AP belongs to the current interface of the router" },
+    { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_NOPREFIX,  "No prefix information available" },
+    { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_NOSUPPORT, "No fast handovers support available" },
+    { 0,                        NULL }
 };
 
 static const value_string names_fmip6_naack_opt_status[] = {
-       { FMIP6_OPT_NEIGHBOR_ADV_ACK_STATUS_INVALID,    "New CoA is invalid" },
-       { FMIP6_OPT_NEIGHBOR_ADV_ACK_STATUS_INVALID_NEW,        "New CoA is invalid, use the supplied CoA" },
-       { FMIP6_OPT_NEIGHBOR_ADV_ACK_STATUS_UNRECOGNIZED,       "LLA is unrecognized" },
-       { 0,                    NULL }
+    { FMIP6_OPT_NEIGHBOR_ADV_ACK_STATUS_INVALID,        "New CoA is invalid" },
+    { FMIP6_OPT_NEIGHBOR_ADV_ACK_STATUS_INVALID_NEW,    "New CoA is invalid, use the supplied CoA" },
+    { FMIP6_OPT_NEIGHBOR_ADV_ACK_STATUS_UNRECOGNIZED,   "LLA is unrecognized" },
+    { 0,                        NULL }
+};
+
+static const value_string fmip6_opt_type_str[] = {
+    { FMIP6_OPT_IP_ADDRESS,             "IP Address" },
+    { FMIP6_OPT_NEW_ROUTER_PREFIX_INFO, "New Router Prefix Information" },
+    { FMIP6_OPT_LINK_LAYER_ADDRESS,     "Link-layer Address" },
+    { 0, NULL }
 };
 
 /* http://www.iana.org/assignments/icmpv6-parameters */
 static const value_string option_vals[] = {
-       { ND_OPT_SOURCE_LINKADDR,                       "Source link-layer address" },
-       { ND_OPT_TARGET_LINKADDR,                       "Target link-layer address" },
-       { ND_OPT_PREFIX_INFORMATION,            "Prefix information" },
-       { ND_OPT_REDIRECTED_HEADER,                     "Redirected header" },
-       { ND_OPT_MTU,                                           "MTU" },
-       { ND_OPT_ADVINTERVAL,                           "Advertisement Interval" },
-       { ND_OPT_HOMEAGENT_INFO,                        "Home Agent Information" },
-       { ND_OPT_CGA,                                           "CGA" },                                                                /* [RFC3971] */
-       { ND_OPT_RSA,                                           "RSA Signature" },                                              /* [RFC3971] */
-       { ND_OPT_TIMESTAMP,                                     "Timestamp" },                                                  /* [RFC3971] */
-       { ND_OPT_NONCE,                                         "Nonce" },                                                                                                              /* [RFC3971] */
-       { ND_OPT_TRUST_ANCHOR,                          "Trust Anchor" },                                                                                               /* [RFC3971] */
-       { 16,           "Certificate" },                                                                                                /* [RFC3971] */
-       { FMIP6_OPT_IP_ADDRESS,                         "IP Address Option" },                                          /* [RFC4068] */
-       { FMIP6_OPT_NEW_ROUTER_PREFIX_INFO,     "New Router Prefix Information" },                      /* [RFC4068] */
-       { FMIP6_OPT_LINK_LAYER_ADDRESS,         "Link-layer Address" },                                         /* [RFC4068] */
-       { FMIP6_OPT_NEIGHBOR_ADV_ACK,           "Neighbor Advertisement Acknowledgment" },      /* [RFC4068] */
-       { 21,           "CARD Request" },                     /* [RFC4065] */
-       { 22,           "CARD Reply" },                       /* [RFC4065] */
-       { 23,           "MAP" },                              /* [RFC4140] */
-       { ND_OPT_ROUTE_INFO,                            "Route Information" },                /* [RFC4191] */
-       { ND_OPT_RECURSIVE_DNS_SERVER,          "Recursive DNS Server" },             /* [RFC5006] */
-       { 26,           "RA Flags Extension" },               /* [RFC5075] */
-       { 27,           "Handover Key Request" },             /* [RFC-ietf-mipshop-handover-key-03.txt] */
-       { 28,           "Handover Key Reply" },               /* [RFC-ietf-mipshop-handover-key-03.txt] */
-       { ND_OPT_MAP,                                           "HMIPv6 MAP option" },
+    { ND_OPT_SOURCE_LINKADDR,           "Source link-layer address" },
+    { ND_OPT_TARGET_LINKADDR,           "Target link-layer address" },
+    { ND_OPT_PREFIX_INFORMATION,        "Prefix information" },
+    { ND_OPT_REDIRECTED_HEADER,         "Redirected header" },
+    { ND_OPT_MTU,                       "MTU" },
+    { ND_OPT_ADVINTERVAL,               "Advertisement Interval" },
+    { ND_OPT_HOMEAGENT_INFO,            "Home Agent Information" },
+    { ND_OPT_CGA,                       "CGA" },                                    /* [RFC3971] */
+    { ND_OPT_RSA,                       "RSA Signature" },                          /* [RFC3971] */
+    { ND_OPT_TIMESTAMP,                 "Timestamp" },                              /* [RFC3971] */
+    { ND_OPT_NONCE,                     "Nonce" },                                  /* [RFC3971] */
+    { ND_OPT_TRUST_ANCHOR,              "Trust Anchor" },                           /* [RFC3971] */
+    { 16,                               "Certificate" },                            /* [RFC3971] */
+    { FMIP6_OPT_IP_ADDRESS,             "IP Address Option" },                      /* [RFC4068] */
+    { FMIP6_OPT_NEW_ROUTER_PREFIX_INFO, "New Router Prefix Information" },          /* [RFC4068] */
+    { FMIP6_OPT_LINK_LAYER_ADDRESS,     "Link-layer Address" },                     /* [RFC4068] */
+    { FMIP6_OPT_NEIGHBOR_ADV_ACK,       "Neighbor Advertisement Acknowledgment" },  /* [RFC4068] */
+    { 21,                               "CARD Request" },                           /* [RFC4065] */
+    { 22,                               "CARD Reply" },                             /* [RFC4065] */
+    { 23,                               "MAP" },                                    /* [RFC4140] */
+    { ND_OPT_ROUTE_INFO,                "Route Information" },                      /* [RFC4191] */
+    { ND_OPT_RECURSIVE_DNS_SERVER,      "Recursive DNS Server" },                   /* [RFC5006] */
+    { 26,                               "RA Flags Extension" },                     /* [RFC5075] */
+    { 27,                               "Handover Key Request" },                   /* [RFC-ietf-mipshop-handover-key-03.txt] */
+    { 28,                               "Handover Key Reply" },                     /* [RFC-ietf-mipshop-handover-key-03.txt] */
+    { ND_OPT_MAP,                       "HMIPv6 MAP option" },
 /*29-252  Unassigned */
-       { 253,          "RFC3692-style Experiment 1" },          /* [RFC4727] */
-       { 254,          "RFC3692-style Experiment 2" },          /* [RFC4727] */
-       { 0,                    NULL }
+    { 253,                              "RFC3692-style Experiment 1" },             /* [RFC4727] */
+    { 254,                              "RFC3692-style Experiment 2" },             /* [RFC4727] */
+    { 0,                                NULL }
 };
 
 static const value_string icmpv6_option_name_type_vals[] = {
-       { 1,    "DER Encoded X.501 Name" },
-       { 2,    "FQDN" },
-       { 0,                    NULL }
+    { 1,    "DER Encoded X.501 Name" },
+    { 2,    "FQDN" },
+    { 0,    NULL }
 };
 
 static const value_string icmpv6_option_cert_type_vals[] = {
-       { 1,    "X.509v3 Certificate" },
-       { 0,                    NULL }
+    { 1,    "X.509v3 Certificate" },
+    { 0,    NULL }
 };
 
 static void
@@ -259,14 +330,14 @@ dissect_contained_icmpv6(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tr
     save_in_error_pkt = pinfo->in_error_pkt;
     pinfo->in_error_pkt = TRUE;
 
-    next_tvb = tvb_new_subset(tvb, offset, -1, -1);
+    next_tvb = tvb_new_subset_remaining(tvb, offset);
 
     /* tiny sanity check */
     if ((tvb_get_guint8(tvb, offset) & 0xf0) == 0x60) {
-       /* The contained packet is an IPv6 datagram; dissect it. */
-       call_dissector(ipv6_handle, next_tvb, pinfo, tree);
+        /* The contained packet is an IPv6 datagram; dissect it. */
+        call_dissector(ipv6_handle, next_tvb, pinfo, tree);
     } else
-       call_dissector(data_handle,next_tvb, pinfo, tree);
+        call_dissector(data_handle,next_tvb, pinfo, tree);
 
     /* Restore the "we're inside an error packet" flag. */
     pinfo->in_error_pkt = save_in_error_pkt;
@@ -275,29 +346,26 @@ dissect_contained_icmpv6(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tr
 static void
 dissect_icmpv6ndopt(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
 {
-    proto_tree *icmp6opt_tree, *field_tree, *name_tree;
-    proto_item *ti, *tf, *name_item;
+    proto_tree *icmp6opt_tree, *field_tree, *name_tree, *cga_tree;
+    proto_item *ti, *tf, *name_item, *cga_item;
     struct nd_opt_hdr nd_opt_hdr, *opt;
     int len;
     const char *typename;
     static const guint8 nd_redirect_reserved[6] = {0, 0, 0, 0, 0, 0};
     guint8 nd_redirect_res[6];
-       int opt_offset;
-       guint8 padd_length = 0;
-       int par_len;
-       guint8 name_type = 0;
-       guint8 cert_type = 0;
-       asn1_ctx_t asn1_ctx;
-       guint32 lifetime;
-       guint32 no_of_pars;
-       guint32 i;
-
-    if (!tree)
-       return;
+    int opt_offset;
+    guint8 padd_length = 0;
+    int par_len;
+    guint8 name_type = 0;
+    guint8 cert_type = 0;
+    asn1_ctx_t asn1_ctx;
+    guint32 lifetime;
+    guint32 no_of_pars;
+    guint32 i;
 
 again:
     if ((int)tvb_reported_length(tvb) <= offset)
-       return; /* No more options left */
+        return; /* No more options left */
 
     opt = &nd_opt_hdr;
     tvb_memcpy(tvb, (guint8 *)opt, offset, sizeof *opt);
@@ -308,11 +376,11 @@ again:
     icmp6opt_tree = proto_item_add_subtree(ti, ett_icmpv6opt);
 
     if (len == 0) {
-       proto_tree_add_text(icmp6opt_tree, tvb,
-                           offset + offsetof(struct nd_opt_hdr, nd_opt_len), 1,
-                           "Invalid option length: %u",
-                           opt->nd_opt_len);
-       return; /* we must not try to decode this */
+        proto_tree_add_text(icmp6opt_tree, tvb,
+                            offset + offsetof(struct nd_opt_hdr, nd_opt_len), 1,
+                            "Invalid option length: %u",
+                            opt->nd_opt_len);
+        return; /* we must not try to decode this */
     }
 
     typename = val_to_str(opt->nd_opt_type, option_vals, "Unknown");
@@ -321,403 +389,422 @@ again:
     proto_item_append_text(ti, " (%s)", typename);
 
     /* Option type */
-       proto_tree_add_item(icmp6opt_tree, hf_icmpv6_option_type, tvb,
-               offset + offsetof(struct nd_opt_hdr, nd_opt_type), 1, FALSE);
+    proto_tree_add_item(icmp6opt_tree, hf_icmpv6_option_type, tvb,
+                        offset + offsetof(struct nd_opt_hdr, nd_opt_type), 1, FALSE);
     /* Option length */
     proto_tree_add_uint(icmp6opt_tree, hf_icmpv6_option_length, tvb,
-       offset + offsetof(struct nd_opt_hdr, nd_opt_len), 1,
-       opt->nd_opt_len << 3);
+                        offset + offsetof(struct nd_opt_hdr, nd_opt_len), 1,
+                        opt->nd_opt_len << 3);
 
     /* decode... */
     switch (opt->nd_opt_type) {
     case ND_OPT_SOURCE_LINKADDR:
     case ND_OPT_TARGET_LINKADDR:
-      {
-       int len_local, p;
-
-       p = offset + sizeof(*opt);
-       len_local = (opt->nd_opt_len << 3) - sizeof(*opt);
-       proto_tree_add_text(icmp6opt_tree, tvb,
-           offset + sizeof(*opt), len_local, "Link-layer address: %s",
-           bytestring_to_str(tvb_get_ptr(tvb, p, len_local), len_local, ':'));
-       break;
-      }
+    {
+        int len_local, p;
+
+        p = offset + sizeof(*opt);
+        len_local = (opt->nd_opt_len << 3) - sizeof(*opt);
+        proto_tree_add_text(icmp6opt_tree, tvb,
+                            offset + sizeof(*opt), len_local, "Link-layer address: %s",
+                            bytestring_to_str(tvb_get_ptr(tvb, p, len_local), len_local, ':'));
+        break;
+    }
     case ND_OPT_PREFIX_INFORMATION:
-      {
-       struct nd_opt_prefix_info nd_opt_prefix_info, *pi;
-       int flagoff;
-
-       pi = &nd_opt_prefix_info;
-       tvb_memcpy(tvb, (guint8 *)pi, offset, sizeof *pi);
-       proto_tree_add_text(icmp6opt_tree, tvb,
-           offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_prefix_len),
-           1, "Prefix length: %u", pi->nd_opt_pi_prefix_len);
-
-       flagoff = offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_flags_reserved);
-       tf = proto_tree_add_text(icmp6opt_tree, tvb, flagoff, 1, "Flags: 0x%02x",
-           tvb_get_guint8(tvb, offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_flags_reserved)));
-       field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
-       proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
-           decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
-                   ND_OPT_PI_FLAG_ONLINK, 8, "Onlink", "Not onlink"));
-       proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
-           decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
-                   ND_OPT_PI_FLAG_AUTO, 8, "Auto", "Not auto"));
-       proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
-           decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
-                   ND_OPT_PI_FLAG_ROUTER, 8,
-                   "Router Address", "Not router address"));
-       proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
-           decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
-                   ND_OPT_PI_FLAG_SITEPREF, 8,
-                   "Site prefix", "Not site prefix"));
-       if (pntohl(&pi->nd_opt_pi_valid_time) == 0xffffffff)
-               proto_tree_add_text(icmp6opt_tree, tvb,
-                               offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_valid_time),
-                               4, "Valid lifetime: infinity");
-       else
-               proto_tree_add_text(icmp6opt_tree, tvb,
-                               offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_valid_time),
-                               4, "Valid lifetime: %u",
-                               pntohl(&pi->nd_opt_pi_valid_time));
-       if (pntohl(&pi->nd_opt_pi_preferred_time) == 0xffffffff)
-               proto_tree_add_text(icmp6opt_tree, tvb,
-                               offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_preferred_time),
-                               4, "Preferred lifetime: infinity");
-       else
-               proto_tree_add_text(icmp6opt_tree, tvb,
-                               offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_preferred_time),
-                               4, "Preferred lifetime: %u",
-                               pntohl(&pi->nd_opt_pi_preferred_time));
-       proto_tree_add_text(icmp6opt_tree, tvb,
-           offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_prefix),
-           16, "Prefix: %s", ip6_to_str(&pi->nd_opt_pi_prefix));
-       break;
-      }
+    {
+        struct nd_opt_prefix_info nd_opt_prefix_info, *pi;
+        int flagoff;
+
+        pi = &nd_opt_prefix_info;
+        tvb_memcpy(tvb, (guint8 *)pi, offset, sizeof *pi);
+        proto_tree_add_text(icmp6opt_tree, tvb,
+                            offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_prefix_len),
+                            1, "Prefix length: %u", pi->nd_opt_pi_prefix_len);
+
+        flagoff = offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_flags_reserved);
+        tf = proto_tree_add_text(icmp6opt_tree, tvb, flagoff, 1, "Flags: 0x%02x",
+                                 tvb_get_guint8(tvb, offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_flags_reserved)));
+        field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
+        proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
+                            decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
+                                                    ND_OPT_PI_FLAG_ONLINK, 8, "Onlink", "Not onlink"));
+        proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
+                            decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
+                                                    ND_OPT_PI_FLAG_AUTO, 8, "Auto", "Not auto"));
+        proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
+                            decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
+                                                    ND_OPT_PI_FLAG_ROUTER, 8,
+                                                    "Router Address", "Not router address"));
+        proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
+                            decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
+                                                    ND_OPT_PI_FLAG_SITEPREF, 8,
+                                                    "Site prefix", "Not site prefix"));
+        if (pntohl(&pi->nd_opt_pi_valid_time) == 0xffffffff)
+            proto_tree_add_text(icmp6opt_tree, tvb,
+                                offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_valid_time),
+                                4, "Valid lifetime: infinity");
+        else
+            proto_tree_add_text(icmp6opt_tree, tvb,
+                                offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_valid_time),
+                                4, "Valid lifetime: %u",
+                                pntohl(&pi->nd_opt_pi_valid_time));
+        if (pntohl(&pi->nd_opt_pi_preferred_time) == 0xffffffff)
+            proto_tree_add_text(icmp6opt_tree, tvb,
+                                offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_preferred_time),
+                                4, "Preferred lifetime: infinity");
+        else
+            proto_tree_add_text(icmp6opt_tree, tvb,
+                                offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_preferred_time),
+                                4, "Preferred lifetime: %u",
+                                pntohl(&pi->nd_opt_pi_preferred_time));
+        proto_tree_add_text(icmp6opt_tree, tvb,
+                            offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_prefix),
+                            16, "Prefix: %s", ip6_to_str(&pi->nd_opt_pi_prefix));
+        break;
+    }
     case ND_OPT_REDIRECTED_HEADER:
-       tvb_memcpy(tvb, (guint8 *)&nd_redirect_res, offset + 2, 6);
-       if (memcmp(nd_redirect_res, nd_redirect_reserved, 6) == 0)
-          proto_tree_add_text(icmp6opt_tree, tvb,
-           offset + 2, 6, "Reserved: 0 (correct)");
-       else
-          proto_tree_add_text(icmp6opt_tree, tvb,
-           offset +2, 6, "Reserved: MUST be 0 (incorrect!)");
-       proto_tree_add_text(icmp6opt_tree, tvb,
-           offset + 8, (opt->nd_opt_len << 3) - 8, "Redirected packet");
-       dissect_contained_icmpv6(tvb, offset + 8, pinfo, icmp6opt_tree);
-       break;
+        tvb_memcpy(tvb, (guint8 *)&nd_redirect_res, offset + 2, 6);
+        if (memcmp(nd_redirect_res, nd_redirect_reserved, 6) == 0)
+            proto_tree_add_text(icmp6opt_tree, tvb,
+                                offset + 2, 6, "Reserved: 0 (correct)");
+        else
+            proto_tree_add_text(icmp6opt_tree, tvb,
+                                offset +2, 6, "Reserved: MUST be 0 (incorrect!)");
+        proto_tree_add_text(icmp6opt_tree, tvb,
+                            offset + 8, (opt->nd_opt_len << 3) - 8, "Redirected packet");
+        dissect_contained_icmpv6(tvb, offset + 8, pinfo, icmp6opt_tree);
+        break;
     case ND_OPT_MTU:
-       proto_tree_add_text(icmp6opt_tree, tvb,
-           offset + offsetof(struct nd_opt_mtu, nd_opt_mtu_mtu), 4,
-           "MTU: %u", tvb_get_ntohl(tvb, offset + offsetof(struct nd_opt_mtu, nd_opt_mtu_mtu)));
-       break;
+        proto_tree_add_text(icmp6opt_tree, tvb,
+                            offset + offsetof(struct nd_opt_mtu, nd_opt_mtu_mtu), 4,
+                            "MTU: %u", tvb_get_ntohl(tvb, offset + offsetof(struct nd_opt_mtu, nd_opt_mtu_mtu)));
+        break;
     case ND_OPT_ADVINTERVAL:
-       proto_tree_add_text(icmp6opt_tree, tvb,
-           offset + offsetof(struct nd_opt_adv_int, nd_opt_adv_int_advint), 4,
-           "Advertisement Interval: %u",
-           tvb_get_ntohl(tvb, offset + offsetof(struct nd_opt_adv_int, nd_opt_adv_int_advint)));
-       break;
+        proto_tree_add_text(icmp6opt_tree, tvb,
+                            offset + offsetof(struct nd_opt_adv_int, nd_opt_adv_int_advint), 4,
+                            "Advertisement Interval: %u",
+                            tvb_get_ntohl(tvb, offset + offsetof(struct nd_opt_adv_int, nd_opt_adv_int_advint)));
+        break;
     case ND_OPT_HOMEAGENT_INFO: /* 8 */
-      {
-       struct nd_opt_ha_info pibuf, *pi;
-
-       pi = &pibuf;
-       tvb_memcpy(tvb, (guint8 *)pi, offset, sizeof *pi);
-       proto_tree_add_text(icmp6opt_tree, tvb,
-           offset + offsetof(struct nd_opt_ha_info, nd_opt_ha_info_ha_pref),
-           2, "Home Agent Preference: %d",
-           (gint16)pntohs(&pi->nd_opt_ha_info_ha_pref));
-       proto_tree_add_text(icmp6opt_tree, tvb,
-           offset + offsetof(struct nd_opt_ha_info, nd_opt_ha_info_ha_life),
-           2, "Home Agent Lifetime: %u",
-           pntohs(&pi->nd_opt_ha_info_ha_life));
-       break;
-      }
-       case ND_OPT_CGA: /* 11 */
-               /* RFC 3971 5.1.  CGA Option */
-               /* Pad Length */
-               opt_offset = offset +2;
-               padd_length = tvb_get_guint8(tvb,opt_offset);
-               proto_tree_add_item(icmp6opt_tree, hf_icmpv6_opt_cga_pad_len, tvb, opt_offset, 1, FALSE);
-               opt_offset++;
-               /* Reserved 8 bits */
-               proto_tree_add_text(icmp6opt_tree, tvb,opt_offset,1,"Reserved");
-               opt_offset++;
-               /* CGA Parameters A variable-length field containing the CGA Parameters data
-                * structure described in Section 4 of
-                * "Cryptographically Generated Addresses (CGA)", RFC3972.
-                */
-               par_len = len-4-padd_length;
-               proto_tree_add_item(icmp6opt_tree, hf_icmpv6_opt_cga, tvb, opt_offset, par_len, FALSE);
-               opt_offset = opt_offset + par_len;
-               /* Padding */
-               proto_tree_add_text(icmp6opt_tree, tvb,opt_offset,padd_length,"Padding");
-               break;
-       case ND_OPT_RSA: /* 12 */
-               /*5.2.  RSA Signature Option */
-               opt_offset = offset +2;
-               /* Reserved, A 16-bit field reserved for future use. */
-               proto_tree_add_text(icmp6opt_tree, tvb,opt_offset,2,"Reserved");
-               opt_offset = opt_offset + 2;
-               /* Key Hash
-                * A 128-bit field containing the most significant (leftmost) 128
-                * bits of a SHA-1 [14] hash of the public key used for constructing
-                * the signature.
-                */
-               proto_tree_add_item(icmp6opt_tree, hf_icmpv6_opt_rsa_key_hash, tvb, opt_offset, 16, FALSE);
-               opt_offset = opt_offset + 16;
-               /* Digital Signature */
-               par_len = len - 20;
-               proto_tree_add_text(icmp6opt_tree, tvb,opt_offset,par_len,"Digital Signature + Padding");
-               /* Padding */
-               /* TODO: Calculate padding length and exlude from the signature */
-               break;
-       case ND_OPT_TIMESTAMP: /* 13 */
-               opt_offset = offset +2;
-               /* Reserved A 48-bit field reserved for future use. */
-               proto_tree_add_text(icmp6opt_tree, tvb,opt_offset,6,"Reserved");
-               opt_offset = opt_offset + 6;
-               /* Timestamp
-                * A 64-bit unsigned integer field containing a timestamp.  The value
-                * indicates the number of seconds since January 1, 1970, 00:00 UTC,
-                * by using a fixed point format.  In this format, the integer number
-                * of seconds is contained in the first 48 bits of the field, and the
-                * remaining 16 bits indicate the number of 1/64K fractions of a
-                * second.
-                */
-               proto_tree_add_text(icmp6opt_tree, tvb,opt_offset,6,"Timestamp(number of seconds since January 1, 1970, 00:00 UTC)");
-               opt_offset = opt_offset + 6;
-               proto_tree_add_text(icmp6opt_tree, tvb,opt_offset,2,"Timestamp(1/64K fractions of a second)");
-               break;
-       case ND_OPT_NONCE:
-               /* 5.3.2.  Nonce Option */
-               opt_offset = offset +2;
-               /* Nonce */
-               break;
-       case ND_OPT_TRUST_ANCHOR:
-               opt_offset = offset +2;
-               /* Name Type */
-               name_type = tvb_get_guint8(tvb,opt_offset);
-               proto_tree_add_item(icmp6opt_tree, hf_icmpv6_opt_name_type, tvb, opt_offset, 1, FALSE);
-               opt_offset++;
-               /* Pad Length */
-               padd_length = tvb_get_guint8(tvb,opt_offset);
-               proto_tree_add_item(icmp6opt_tree, hf_icmpv6_opt_cga_pad_len, tvb, opt_offset, 1, FALSE);
-               opt_offset++;
-               par_len = len - 4 - padd_length;
-               switch (name_type){
-               case 1:
-                       /* DER Encoded X.501 Name */
-                       name_item =proto_tree_add_item(icmp6opt_tree, hf_icmpv6_opt_name_x501, tvb, opt_offset, par_len, FALSE);
-                       name_tree = proto_item_add_subtree(name_item, ett_icmpv6opt_name);
-                       asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
-                       dissect_x509if_Name(FALSE, tvb, opt_offset, &asn1_ctx, name_tree, hf_icmpv6_x509if_Name);
-                       break;
-               case 2:
-                       /* FQDN */
-                       proto_tree_add_item(icmp6opt_tree, hf_icmpv6_opt_name_fqdn, tvb, opt_offset, par_len, FALSE);
-                       break;
-               default:
-                       proto_tree_add_text(icmp6opt_tree, tvb,opt_offset, par_len,"Unknown name type");
-                       break;
-               }
-               opt_offset = opt_offset + par_len;
-               /* Padding */
-               proto_tree_add_text(icmp6opt_tree, tvb,opt_offset,padd_length,"Padding");
-               opt_offset = opt_offset + padd_length;
-               break;
-       case ND_OPT_CERTIFICATE:
-               opt_offset = offset +2;
-               /* Cert Type */
-               cert_type = tvb_get_guint8(tvb,opt_offset);
-               proto_tree_add_item(icmp6opt_tree, hf_icmpv6_opt_cert_type, tvb, opt_offset, 1, FALSE);
-               opt_offset++;
-               /* Reserved */
-               proto_tree_add_text(icmp6opt_tree, tvb,opt_offset,1,"Reserved");
-               opt_offset++;
-               /* Certificate */
-
-               if(cert_type == 1){
-                       asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
-                       opt_offset = dissect_x509af_Certificate(FALSE, tvb, opt_offset, &asn1_ctx, icmp6opt_tree, hf_icmpv6_x509af_Certificate);
-                       par_len = len - (opt_offset - offset);
-                       /* Padding */
-                       proto_tree_add_text(icmp6opt_tree, tvb,opt_offset,par_len,"Padding");
-               }else{
-                       par_len = len - 4;
-                       proto_tree_add_text(icmp6opt_tree, tvb,opt_offset,par_len,"Unknown Certificate + padding");
-               }
-
-               break;
+    {
+        struct nd_opt_ha_info pibuf, *pi;
+
+        pi = &pibuf;
+        tvb_memcpy(tvb, (guint8 *)pi, offset, sizeof *pi);
+        proto_tree_add_text(icmp6opt_tree, tvb,
+                            offset + offsetof(struct nd_opt_ha_info, nd_opt_ha_info_ha_pref),
+                            2, "Home Agent Preference: %d",
+                            (gint16)pntohs(&pi->nd_opt_ha_info_ha_pref));
+        proto_tree_add_text(icmp6opt_tree, tvb,
+                            offset + offsetof(struct nd_opt_ha_info, nd_opt_ha_info_ha_life),
+                            2, "Home Agent Lifetime: %u",
+                            pntohs(&pi->nd_opt_ha_info_ha_life));
+        break;
+    }
+    case ND_OPT_CGA: /* 11 */ {
+        guint16 ext_data_len;
+        /* RFC 3971 5.1.  CGA Option */
+        /* Pad Length */
+        opt_offset = offset +2;
+        padd_length = tvb_get_guint8(tvb,opt_offset);
+        proto_tree_add_item(icmp6opt_tree, hf_icmpv6_opt_cga_pad_len, tvb, opt_offset, 1, FALSE);
+        opt_offset++;
+        /* Reserved 8 bits */
+        proto_tree_add_text(icmp6opt_tree, tvb,opt_offset,1,"Reserved");
+        opt_offset++;
+        /* CGA Parameters A variable-length field containing the CGA Parameters data
+         * structure described in Section 4 of
+         * "Cryptographically Generated Addresses (CGA)", RFC3972.
+         */
+        par_len = len-4-padd_length;
+        cga_item = proto_tree_add_item(icmp6opt_tree, hf_icmpv6_opt_cga, tvb, opt_offset, par_len, FALSE);
+        par_len += opt_offset;
+        cga_tree = proto_item_add_subtree(cga_item, ett_cga_param_name);
+        proto_tree_add_item(cga_tree,hf_icmpv6_opt_cga_modifier,tvb, opt_offset,16,FALSE);
+        opt_offset += 16;
+        proto_tree_add_item(cga_tree,hf_icmpv6_opt_cga_subnet_prefix,tvb,opt_offset,8,FALSE);
+        opt_offset += 8;
+        proto_tree_add_item(cga_tree,hf_icmpv6_opt_cga_count,tvb,opt_offset,1,FALSE);
+        opt_offset++;
+        asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
+        opt_offset = dissect_x509af_SubjectPublicKeyInfo(FALSE, tvb, opt_offset, &asn1_ctx, cga_tree, -1);
+        /* Process RFC 4581*/
+        while (opt_offset < par_len) {
+            proto_tree_add_item(cga_tree,hf_icmpv6_opt_cga_ext_type,tvb,opt_offset,2,FALSE);
+            opt_offset += 2;
+            ext_data_len = tvb_get_ntohs(tvb,opt_offset); 
+            proto_tree_add_item(cga_tree,hf_icmpv6_opt_cga_ext_length,tvb,opt_offset,2,FALSE);
+            opt_offset += 2;
+            proto_tree_add_text(cga_tree,tvb,opt_offset,ext_data_len,"Ext Data");
+            opt_offset += ext_data_len;
+        }
+
+        /* Padding */
+        proto_tree_add_text(icmp6opt_tree, tvb,opt_offset,padd_length,"Padding");
+        break;
+    }
+    case ND_OPT_RSA: /* 12 */
+        /*5.2.  RSA Signature Option */
+        opt_offset = offset +2;
+        /* Reserved, A 16-bit field reserved for future use. */
+        proto_tree_add_text(icmp6opt_tree, tvb,opt_offset,2,"Reserved");
+        opt_offset = opt_offset + 2;
+        /* Key Hash
+         * A 128-bit field containing the most significant (leftmost) 128
+         * bits of a SHA-1 [14] hash of the public key used for constructing
+         * the signature.
+         */
+        proto_tree_add_item(icmp6opt_tree, hf_icmpv6_opt_rsa_key_hash, tvb, opt_offset, 16, FALSE);
+        opt_offset = opt_offset + 16;
+        /* Digital Signature */
+        par_len = len - 20;
+        proto_tree_add_text(icmp6opt_tree, tvb,opt_offset,par_len,"Digital Signature + Padding");
+        /* Padding */
+        /* TODO: Calculate padding length and exlude from the signature */
+        break;
+    case ND_OPT_TIMESTAMP: /* 13 */
+        opt_offset = offset +2;
+        /* Reserved A 48-bit field reserved for future use. */
+        proto_tree_add_text(icmp6opt_tree, tvb,opt_offset,6,"Reserved");
+        opt_offset = opt_offset + 6;
+        /* Timestamp
+         * A 64-bit unsigned integer field containing a timestamp.  The value
+         * indicates the number of seconds since January 1, 1970, 00:00 UTC,
+         * by using a fixed point format.  In this format, the integer number
+         * of seconds is contained in the first 48 bits of the field, and the
+         * remaining 16 bits indicate the number of 1/64K fractions of a
+         * second.
+         */
+        proto_tree_add_text(icmp6opt_tree, tvb,opt_offset,6,"Timestamp(number of seconds since January 1, 1970, 00:00 UTC)");
+        opt_offset = opt_offset + 6;
+        proto_tree_add_text(icmp6opt_tree, tvb,opt_offset,2,"Timestamp(1/64K fractions of a second)");
+        break;
+    case ND_OPT_NONCE:
+        /* 5.3.2.  Nonce Option */
+        opt_offset = offset +2;
+        proto_tree_add_text(icmp6opt_tree, tvb,opt_offset,len-2,"Nonce");
+        /* Nonce */
+        break;
+    case ND_OPT_TRUST_ANCHOR:
+        opt_offset = offset +2;
+        /* Name Type */
+        name_type = tvb_get_guint8(tvb,opt_offset);
+        proto_tree_add_item(icmp6opt_tree, hf_icmpv6_opt_name_type, tvb, opt_offset, 1, FALSE);
+        opt_offset++;
+        /* Pad Length */
+        padd_length = tvb_get_guint8(tvb,opt_offset);
+        proto_tree_add_item(icmp6opt_tree, hf_icmpv6_opt_cga_pad_len, tvb, opt_offset, 1, FALSE);
+        opt_offset++;
+        par_len = len - 4 - padd_length;
+        switch (name_type){
+        case 1:
+            /* DER Encoded X.501 Name */
+            name_item =proto_tree_add_item(icmp6opt_tree, hf_icmpv6_opt_name_x501, tvb, opt_offset, par_len, FALSE);
+            name_tree = proto_item_add_subtree(name_item, ett_icmpv6opt_name);
+            asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
+            dissect_x509if_Name(FALSE, tvb, opt_offset, &asn1_ctx, name_tree, hf_icmpv6_x509if_Name);
+            break;
+        case 2:
+            /* FQDN */
+            proto_tree_add_item(icmp6opt_tree, hf_icmpv6_opt_name_fqdn, tvb, opt_offset, par_len, FALSE);
+            break;
+        default:
+            proto_tree_add_text(icmp6opt_tree, tvb,opt_offset, par_len,"Unknown name type");
+            break;
+        }
+        opt_offset = opt_offset + par_len;
+        /* Padding */
+        proto_tree_add_text(icmp6opt_tree, tvb,opt_offset,padd_length,"Padding");
+        opt_offset = opt_offset + padd_length;
+        break;
+    case ND_OPT_CERTIFICATE:
+        opt_offset = offset +2;
+        /* Cert Type */
+        cert_type = tvb_get_guint8(tvb,opt_offset);
+        proto_tree_add_item(icmp6opt_tree, hf_icmpv6_opt_cert_type, tvb, opt_offset, 1, FALSE);
+        opt_offset++;
+        /* Reserved */
+        proto_tree_add_text(icmp6opt_tree, tvb,opt_offset,1,"Reserved");
+        opt_offset++;
+        /* Certificate */
+
+        if(cert_type == 1){
+            asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
+            opt_offset = dissect_x509af_Certificate(FALSE, tvb, opt_offset, &asn1_ctx, icmp6opt_tree, hf_icmpv6_x509af_Certificate);
+            par_len = len - (opt_offset - offset);
+            /* Padding */
+            proto_tree_add_text(icmp6opt_tree, tvb,opt_offset,par_len,"Padding");
+        }else{
+            par_len = len - 4;
+            proto_tree_add_text(icmp6opt_tree, tvb,opt_offset,par_len,"Unknown Certificate + padding");
+        }
+        break;
     case ND_OPT_MAP:
-      {
-       struct nd_opt_map_info mapbuf, *map;
-       int flagoff;
-
-       map = &mapbuf;
-       tvb_memcpy(tvb, (guint8 *)map, offset, sizeof *map);
-       proto_tree_add_text(icmp6opt_tree, tvb,
-           offset + offsetof(struct nd_opt_map_info, nd_opt_map_dist_and_pref),
-           1, "Distance: %u", (map->nd_opt_map_dist_and_pref >> 4));
-       proto_tree_add_text(icmp6opt_tree, tvb,
-           offset + offsetof(struct nd_opt_map_info, nd_opt_map_dist_and_pref),
-           1, "Preference: %u", (map->nd_opt_map_dist_and_pref & 0x0F));
-       flagoff = offset + offsetof(struct nd_opt_map_info,
-           nd_opt_map_flags);
-       tf = proto_tree_add_text(icmp6opt_tree, tvb, flagoff, 1,
-           "Flags: 0x%02x",
-           tvb_get_guint8(tvb, offset + offsetof(struct nd_opt_map_info,
-           nd_opt_map_flags)));
-       field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
-       proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
-           decode_boolean_bitfield(map->nd_opt_map_flags,
-               ND_OPT_MAP_FLAG_R, 8, "R", "No R"));
-       proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
-           decode_boolean_bitfield(map->nd_opt_map_flags,
-               ND_OPT_MAP_FLAG_M, 8, "M", "No M"));
-       proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
-           decode_boolean_bitfield(map->nd_opt_map_flags,
-               ND_OPT_MAP_FLAG_I, 8, "I", "No I"));
-       proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
-           decode_boolean_bitfield(map->nd_opt_map_flags,
-               ND_OPT_MAP_FLAG_T, 8, "T", "No T"));
-       proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
-           decode_boolean_bitfield(map->nd_opt_map_flags,
-               ND_OPT_MAP_FLAG_P, 8, "P", "No P"));
-       proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
-           decode_boolean_bitfield(map->nd_opt_map_flags,
-               ND_OPT_MAP_FLAG_V, 8, "V", "No V"));
-       proto_tree_add_text(icmp6opt_tree, tvb,
-           offset + offsetof(struct nd_opt_map_info, nd_opt_map_lifetime),
-           4, "Lifetime: %u", pntohl(&map->nd_opt_map_lifetime));
-
-       proto_tree_add_text(icmp6opt_tree, tvb,
-           offset + offsetof(struct nd_opt_map_info, nd_opt_map_address), 16,
+    {
+        struct nd_opt_map_info mapbuf, *map;
+        int flagoff;
+
+        map = &mapbuf;
+        tvb_memcpy(tvb, (guint8 *)map, offset, sizeof *map);
+        proto_tree_add_text(icmp6opt_tree, tvb,
+                            offset + offsetof(struct nd_opt_map_info, nd_opt_map_dist_and_pref),
+                            1, "Distance: %u", (map->nd_opt_map_dist_and_pref >> 4));
+        proto_tree_add_text(icmp6opt_tree, tvb,
+                            offset + offsetof(struct nd_opt_map_info, nd_opt_map_dist_and_pref),
+                            1, "Preference: %u", (map->nd_opt_map_dist_and_pref & 0x0F));
+        flagoff = offset + offsetof(struct nd_opt_map_info,
+                                    nd_opt_map_flags);
+        tf = proto_tree_add_text(icmp6opt_tree, tvb, flagoff, 1,
+                                 "Flags: 0x%02x",
+                                 tvb_get_guint8(tvb, offset + offsetof(struct nd_opt_map_info,
+                                                                       nd_opt_map_flags)));
+        field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
+        proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
+                            decode_boolean_bitfield(map->nd_opt_map_flags,
+                                                    ND_OPT_MAP_FLAG_R, 8, "R", "No R"));
+        proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
+                            decode_boolean_bitfield(map->nd_opt_map_flags,
+                                                    ND_OPT_MAP_FLAG_M, 8, "M", "No M"));
+        proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
+                            decode_boolean_bitfield(map->nd_opt_map_flags,
+                                                    ND_OPT_MAP_FLAG_I, 8, "I", "No I"));
+        proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
+                            decode_boolean_bitfield(map->nd_opt_map_flags,
+                                                    ND_OPT_MAP_FLAG_T, 8, "T", "No T"));
+        proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
+                            decode_boolean_bitfield(map->nd_opt_map_flags,
+                                                    ND_OPT_MAP_FLAG_P, 8, "P", "No P"));
+        proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
+                            decode_boolean_bitfield(map->nd_opt_map_flags,
+                                                    ND_OPT_MAP_FLAG_V, 8, "V", "No V"));
+        proto_tree_add_text(icmp6opt_tree, tvb,
+                            offset + offsetof(struct nd_opt_map_info, nd_opt_map_lifetime),
+                            4, "Lifetime: %u", pntohl(&map->nd_opt_map_lifetime));
+
+        proto_tree_add_text(icmp6opt_tree, tvb,
+                            offset + offsetof(struct nd_opt_map_info, nd_opt_map_address), 16,
 #ifdef INET6
-           "Address of MAP: %s (%s)",
-           get_hostname6(&map->nd_opt_map_address),
+                            "Address of MAP: %s (%s)",
+                            get_hostname6(&map->nd_opt_map_address),
 #else
-           "Address of MAP: %s",
+                            "Address of MAP: %s",
 #endif
-           ip6_to_str(&map->nd_opt_map_address));
-       break;
-      }
+                            ip6_to_str(&map->nd_opt_map_address));
+        break;
+    }
     case ND_OPT_ROUTE_INFO:
-      {
-       struct nd_opt_route_info ribuf, *ri;
-       struct e_in6_addr in6;
-       int l;
-       guint32 lifetime_local;
-
-       ri = &ribuf;
-       tvb_memcpy(tvb, (guint8 *)ri, offset, sizeof *ri);
-       memset(&in6, 0, sizeof(in6));
-       switch (ri->nd_opt_rti_len) {
-       case 1:
-           l = 0;
-           break;
-       case 2:
-           tvb_memcpy(tvb, (guint8 *)&in6, offset + sizeof(*ri), l = 8);
-           break;
-       case 3:
-           tvb_memcpy(tvb, (guint8 *)&in6, offset + sizeof(*ri), l = 16);
-           break;
-       default:
-           l = -1;
-           break;
-       }
-       if (l >= 0) {
-           proto_tree_add_text(icmp6opt_tree, tvb,
-               offset + offsetof(struct nd_opt_route_info, nd_opt_rti_prefixlen),
-               1, "Prefix length: %u", ri->nd_opt_rti_prefixlen);
-           tf = proto_tree_add_text(icmp6opt_tree, tvb,
-               offset + offsetof(struct nd_opt_route_info, nd_opt_rti_flags),
-               1, "Flags: 0x%02x", ri->nd_opt_rti_flags);
-           field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
-           proto_tree_add_text(field_tree, tvb,
-               offset + offsetof(struct nd_opt_route_info, nd_opt_rti_flags),
-               1, "%s",
-               decode_enumerated_bitfield(ri->nd_opt_rti_flags,
-                   ND_RA_FLAG_RTPREF_MASK, 8, names_router_pref,
-                   "Router preference: %s"));
-           lifetime_local = pntohl(&ri->nd_opt_rti_lifetime);
-           if (lifetime_local == 0xffffffff)
-               proto_tree_add_text(icmp6opt_tree, tvb,
-                   offset + offsetof(struct nd_opt_route_info, nd_opt_rti_lifetime),
-                   sizeof(ri->nd_opt_rti_lifetime), "Lifetime: infinity");
-           else
-               proto_tree_add_text(icmp6opt_tree, tvb,
-                   offset + offsetof(struct nd_opt_route_info, nd_opt_rti_lifetime),
-                   sizeof(ri->nd_opt_rti_lifetime), "Lifetime: %u", lifetime_local);
-           proto_tree_add_text(icmp6opt_tree, tvb,
-               offset + sizeof(*ri), l, "Prefix: %s", ip6_to_str(&in6));
-       } else {
-           proto_tree_add_text(icmp6opt_tree, tvb,
-               offset + offsetof(struct nd_opt_hdr, nd_opt_len), 1,
-               "Invalid option length: %u", opt->nd_opt_len);
-       }
-       break;
-      }
-
+    {
+        struct nd_opt_route_info ribuf, *ri;
+        struct e_in6_addr in6;
+        int l;
+        guint32 lifetime_local;
+
+        ri = &ribuf;
+        tvb_memcpy(tvb, (guint8 *)ri, offset, sizeof *ri);
+        memset(&in6, 0, sizeof(in6));
+        switch (ri->nd_opt_rti_len) {
+        case 1:
+            l = 0;
+            break;
+        case 2:
+            tvb_memcpy(tvb, (guint8 *)&in6, offset + sizeof(*ri), l = 8);
+            break;
+        case 3:
+            tvb_memcpy(tvb, (guint8 *)&in6, offset + sizeof(*ri), l = 16);
+            break;
+        default:
+            l = -1;
+            break;
+        }
+        if (l >= 0) {
+            proto_tree_add_text(icmp6opt_tree, tvb,
+                                offset + offsetof(struct nd_opt_route_info, nd_opt_rti_prefixlen),
+                                1, "Prefix length: %u", ri->nd_opt_rti_prefixlen);
+            tf = proto_tree_add_text(icmp6opt_tree, tvb,
+                                     offset + offsetof(struct nd_opt_route_info, nd_opt_rti_flags),
+                                     1, "Flags: 0x%02x", ri->nd_opt_rti_flags);
+            field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
+            proto_tree_add_text(field_tree, tvb,
+                                offset + offsetof(struct nd_opt_route_info, nd_opt_rti_flags),
+                                1, "%s",
+                                decode_enumerated_bitfield(ri->nd_opt_rti_flags,
+                                                           ND_RA_FLAG_RTPREF_MASK, 8, names_router_pref,
+                                                           "Router preference: %s"));
+            lifetime_local = pntohl(&ri->nd_opt_rti_lifetime);
+            if (lifetime_local == 0xffffffff)
+                proto_tree_add_text(icmp6opt_tree, tvb,
+                                    offset + offsetof(struct nd_opt_route_info, nd_opt_rti_lifetime),
+                                    sizeof(ri->nd_opt_rti_lifetime), "Lifetime: infinity");
+            else
+                proto_tree_add_text(icmp6opt_tree, tvb,
+                                    offset + offsetof(struct nd_opt_route_info, nd_opt_rti_lifetime),
+                                    sizeof(ri->nd_opt_rti_lifetime), "Lifetime: %u", lifetime_local);
+            proto_tree_add_text(icmp6opt_tree, tvb,
+                                offset + sizeof(*ri), l, "Prefix: %s", ip6_to_str(&in6));
+        } else {
+            proto_tree_add_text(icmp6opt_tree, tvb,
+                                offset + offsetof(struct nd_opt_hdr, nd_opt_len), 1,
+                                "Invalid option length: %u", opt->nd_opt_len);
+        }
+        break;
+    }
     case FMIP6_OPT_NEIGHBOR_ADV_ACK:
-               {
-                       struct fmip6_opt_neighbor_advertisement_ack fmip6_opt_neighbor_advertisement_ack, *opt_naack;
-                       struct e_in6_addr in6;
-
-                       opt_naack = &fmip6_opt_neighbor_advertisement_ack;
-                       tvb_memcpy(tvb, (guint8 *)opt_naack, offset, sizeof *opt_naack);
-
-                       proto_tree_add_text(icmp6opt_tree, tvb,
-                               offset + offsetof(struct fmip6_opt_neighbor_advertisement_ack, fmip6_opt_optcode),
-                               1, "Option-Code: %u",
-                               opt_naack->fmip6_opt_optcode);
-
-                       proto_tree_add_text(icmp6opt_tree, tvb,
-                               offset + offsetof(struct fmip6_opt_neighbor_advertisement_ack, fmip6_opt_status),
-                               1, "Status: %s",
-                               val_to_str(opt_naack->fmip6_opt_status, names_fmip6_naack_opt_status, "Unknown"));
-
-                       if (opt_naack->fmip6_opt_len == 3){
-                               tvb_memcpy(tvb, (guint8 *)&in6, offset + sizeof(*opt_naack), 16);
-                               proto_tree_add_text(icmp6opt_tree, tvb,
-                               offset + sizeof(*opt_naack),
-                               16, "New Care-of Address: %s",
-                               ip6_to_str(&in6));
-                       }
-
-               break;
-               }
-               case ND_OPT_RECURSIVE_DNS_SERVER:
-
-                       opt_offset = offset + 2;
-                       proto_tree_add_text(icmp6opt_tree, tvb, opt_offset ,2 ,"Reserved");
-                       opt_offset = opt_offset + 2;
-                       /* A value of all one bits (0xffffffff) represents infinity.  A value of
-                        * zero means that the RDNSS address MUST no longer be used.
-                        */
-                       lifetime = tvb_get_ntohl(tvb, opt_offset);
-                       if (lifetime == 0xffffffff){
-                               proto_tree_add_text(icmp6opt_tree, tvb, opt_offset ,4 ,"Lifetime: infinity");
-                       }else{ 
-                               if(lifetime==0){
-                                       proto_tree_add_text(icmp6opt_tree, tvb, opt_offset ,4 ,"Lifetime: RDNSS address MUST no longer be used");
-                               }else{
-                                       proto_tree_add_text(icmp6opt_tree, tvb, opt_offset ,4 ,"Lifetime: %u", lifetime);
-                               }
-                       }
-                       opt_offset = opt_offset+4;
-                       /* Addresses of IPv6 Recursive DNS Servers */
-                       no_of_pars = opt->nd_opt_len - 1;
-                       no_of_pars = no_of_pars >> 2;
-
-                       for (i = 0; i <= no_of_pars; i++) {                     
-                               proto_tree_add_item(icmp6opt_tree, hf_icmpv6_recursive_dns_serv, tvb, opt_offset, 16, FALSE);
-                               opt_offset = opt_offset+16;
-                       }
-
-
-                       break;
-               }
+    {
+        struct fmip6_opt_neighbor_advertisement_ack fmip6_opt_neighbor_advertisement_ack, *opt_naack;
+        struct e_in6_addr in6;
+
+        opt_naack = &fmip6_opt_neighbor_advertisement_ack;
+        tvb_memcpy(tvb, (guint8 *)opt_naack, offset, sizeof *opt_naack);
+
+        proto_tree_add_text(icmp6opt_tree, tvb,
+                            offset + offsetof(struct fmip6_opt_neighbor_advertisement_ack, fmip6_opt_optcode),
+                            1, "Option-Code: %u",
+                            opt_naack->fmip6_opt_optcode);
+
+        proto_tree_add_text(icmp6opt_tree, tvb,
+                            offset + offsetof(struct fmip6_opt_neighbor_advertisement_ack, fmip6_opt_status),
+                            1, "Status: %s",
+                            val_to_str(opt_naack->fmip6_opt_status, names_fmip6_naack_opt_status, "Unknown"));
+
+        if (opt_naack->fmip6_opt_len == 3){
+            tvb_memcpy(tvb, (guint8 *)&in6, offset + sizeof(*opt_naack), 16);
+            proto_tree_add_text(icmp6opt_tree, tvb,
+                                offset + sizeof(*opt_naack),
+                                16, "New Care-of Address: %s",
+                                ip6_to_str(&in6));
+        }
+
+        break;
+    }
+    case ND_OPT_RECURSIVE_DNS_SERVER:
+
+        opt_offset = offset + 2;
+        proto_tree_add_text(icmp6opt_tree, tvb, opt_offset ,2 ,"Reserved");
+        opt_offset = opt_offset + 2;
+        /* A value of all one bits (0xffffffff) represents infinity.  A value of
+         * zero means that the RDNSS address MUST no longer be used.
+         */
+        lifetime = tvb_get_ntohl(tvb, opt_offset);
+        if (lifetime == 0xffffffff){
+            proto_tree_add_text(icmp6opt_tree, tvb, opt_offset ,4 ,"Lifetime: infinity");
+        }else{ 
+            if(lifetime==0){
+                proto_tree_add_text(icmp6opt_tree, tvb, opt_offset ,4 ,"Lifetime: RDNSS address MUST no longer be used");
+            }else{
+                proto_tree_add_text(icmp6opt_tree, tvb, opt_offset ,4 ,"Lifetime: %u", lifetime);
+            }
+        }
+        opt_offset = opt_offset+4;
+        /* Addresses of IPv6 Recursive DNS Servers */
+        no_of_pars = opt->nd_opt_len - 1;
+        no_of_pars = no_of_pars >> 2;
+
+        for (i = 0; i <= no_of_pars; i++) {                     
+            proto_tree_add_item(icmp6opt_tree, hf_icmpv6_recursive_dns_serv, tvb, opt_offset, 16, FALSE);
+            opt_offset = opt_offset+16;
+        }
+        break;
+    } /* switch (opt->nd_opt_type) */
 
     offset += (opt->nd_opt_len << 3);
 
@@ -729,119 +816,106 @@ again:
 static void
 dissect_icmpv6fmip6opt(tvbuff_t *tvb, int offset, proto_tree *tree)
 {
-       proto_tree *icmp6opt_tree;
-       proto_item *ti;
-       struct fmip6_opt_hdr fmip6_opt_hdr, *opt;
-       int len;
-       const char *typename;
+    proto_tree *icmp6opt_tree;
+    proto_item *ti;
+    struct fmip6_opt_hdr fmip6_opt_hdr, *opt;
+    int len;
+    const char *typename;
 
-       if (!tree)
-               return;
+    if (!tree)
+        return;
 
 again:
-       if ((int)tvb_reported_length(tvb) <= offset)
-               return; /* No more options left */
-
-       opt = &fmip6_opt_hdr;
-       tvb_memcpy(tvb, (guint8 *)opt, offset, sizeof *opt);
-       len = opt->fmip6_opt_len << 3;
-
-       /* !!! specify length */
-       ti = proto_tree_add_text(tree, tvb, offset, len, "ICMPv6 options");
-       icmp6opt_tree = proto_item_add_subtree(ti, ett_icmpv6opt);
-
-       if (len == 0) {
-               proto_tree_add_text(icmp6opt_tree, tvb,
-                               offset + offsetof(struct fmip6_opt_hdr, fmip6_opt_len), 1,
-                               "Invalid option length: %u",
-                               opt->fmip6_opt_len);
-               return; /* we must not try to decode this */
-       }
-
-       switch (opt->fmip6_opt_type) {
-               case FMIP6_OPT_IP_ADDRESS:
-                       typename = "IP Address";
-                       break;
-               case FMIP6_OPT_NEW_ROUTER_PREFIX_INFO:
-                       typename = "New Router Prefix Information";
-                       break;
-               case FMIP6_OPT_LINK_LAYER_ADDRESS:
-                       typename = "Link-layer Address";
-                       break;
-               default:
-                       typename = "Unknown";
-                       break;
-       }
-
-       proto_tree_add_text(icmp6opt_tree, tvb,
-                       offset + offsetof(struct fmip6_opt_hdr, fmip6_opt_type), 1,
-                       "Type: %u (%s)", opt->fmip6_opt_type, typename);
-       proto_tree_add_text(icmp6opt_tree, tvb,
-                       offset + offsetof(struct fmip6_opt_hdr, fmip6_opt_len), 1,
-                       "Length: %u bytes (%u)", opt->fmip6_opt_len << 3, opt->fmip6_opt_len);
-
-       /* decode... */
-       switch (opt->fmip6_opt_type) {
-               case FMIP6_OPT_IP_ADDRESS:
-                       {
-                               struct fmip6_opt_ip_address fmip6_opt_ip_address, *opt_ip;
-
-                               opt_ip = &fmip6_opt_ip_address;
-                               tvb_memcpy(tvb, (guint8 *)opt_ip, offset, sizeof *opt_ip);
-
-                               proto_tree_add_text(icmp6opt_tree, tvb,
-                                               offset + offsetof(struct fmip6_opt_hdr, fmip6_opt_optcode), 1, "Option-Code: %s",
-                                               val_to_str(opt->fmip6_opt_optcode, names_fmip6_ip_addr_opt_code, "Unknown"));
-
-                               proto_tree_add_text(icmp6opt_tree, tvb,
-                                               offset + offsetof(struct fmip6_opt_ip_address, fmip6_opt_prefix_len),
-                                               1, "Prefix length: %u", opt_ip->fmip6_opt_prefix_len);
-
-                               proto_tree_add_text(icmp6opt_tree, tvb,
-                                               offset + offsetof(struct fmip6_opt_ip_address, fmip6_opt_ip6_address),
-                                               16, "IPv6 Address: %s",
-                                               ip6_to_str(&opt_ip->fmip6_opt_ip6_address));
-                               break;
-                       }
-               case FMIP6_OPT_NEW_ROUTER_PREFIX_INFO:
-                       {
-                               struct fmip6_opt_new_router_prefix_info fmip6_opt_new_router_prefix_info, *opt_nr;
-
-                               opt_nr = &fmip6_opt_new_router_prefix_info;
-                               tvb_memcpy(tvb, (guint8 *)opt_nr, offset, sizeof *opt_nr);
-
-                               proto_tree_add_text(icmp6opt_tree, tvb,
-                                               offset + offsetof(struct fmip6_opt_hdr, fmip6_opt_optcode), 1, "Option-Code: %u",
-                                               opt->fmip6_opt_optcode);
-
-                               proto_tree_add_text(icmp6opt_tree, tvb,
-                                               offset + offsetof(struct fmip6_opt_new_router_prefix_info, fmip6_opt_prefix_len),
-                                               1, "Prefix length: %u", opt_nr->fmip6_opt_prefix_len);
-
-                               proto_tree_add_text(icmp6opt_tree, tvb,
-                                               offset + offsetof(struct fmip6_opt_new_router_prefix_info, fmip6_opt_prefix),
-                                               16, "Prefix: %s",
-                                               ip6_to_str(&opt_nr->fmip6_opt_prefix));
-                               break;
-                       }
-               case FMIP6_OPT_LINK_LAYER_ADDRESS:
-                       {
-                               int len_local, p;
-
-                               p = offset + sizeof(*opt);
-                               proto_tree_add_text(icmp6opt_tree, tvb,
-                                               offset + offsetof(struct fmip6_opt_hdr, fmip6_opt_optcode), 1, "Option-Code: %s",
-                                               val_to_str(opt->fmip6_opt_optcode, names_fmip6_lla_opt_code, "Unknown"));
-                               len_local = (opt->fmip6_opt_len << 3) - sizeof(*opt);
-                               proto_tree_add_text(icmp6opt_tree, tvb,
-                                               offset + sizeof(*opt), len_local, "Link-layer address: %s",
-                                               bytestring_to_str(tvb_get_ptr(tvb, p, len_local), len_local, ':'));
-                               break;
-                       }
-       }
-
-       offset += (opt->fmip6_opt_len << 3);
-       goto again;
+    if ((int)tvb_reported_length(tvb) <= offset)
+        return; /* No more options left */
+
+    opt = &fmip6_opt_hdr;
+    tvb_memcpy(tvb, (guint8 *)opt, offset, sizeof *opt);
+    len = opt->fmip6_opt_len << 3;
+
+    /* !!! specify length */
+    ti = proto_tree_add_text(tree, tvb, offset, len, "ICMPv6 options");
+    icmp6opt_tree = proto_item_add_subtree(ti, ett_icmpv6opt);
+
+    if (len == 0) {
+        proto_tree_add_text(icmp6opt_tree, tvb,
+                            offset + offsetof(struct fmip6_opt_hdr, fmip6_opt_len), 1,
+                            "Invalid option length: %u",
+                            opt->fmip6_opt_len);
+        return; /* we must not try to decode this */
+    }
+
+    typename = val_to_str (opt->fmip6_opt_type, fmip6_opt_type_str, "Unknown");
+
+    proto_tree_add_text(icmp6opt_tree, tvb,
+                        offset + offsetof(struct fmip6_opt_hdr, fmip6_opt_type), 1,
+                        "Type: %u (%s)", opt->fmip6_opt_type, typename);
+    proto_tree_add_text(icmp6opt_tree, tvb,
+                        offset + offsetof(struct fmip6_opt_hdr, fmip6_opt_len), 1,
+                        "Length: %u bytes (%u)", opt->fmip6_opt_len << 3, opt->fmip6_opt_len);
+
+    /* decode... */
+    switch (opt->fmip6_opt_type) {
+    case FMIP6_OPT_IP_ADDRESS:
+    {
+        struct fmip6_opt_ip_address fmip6_opt_ip_address, *opt_ip;
+
+        opt_ip = &fmip6_opt_ip_address;
+        tvb_memcpy(tvb, (guint8 *)opt_ip, offset, sizeof *opt_ip);
+
+        proto_tree_add_text(icmp6opt_tree, tvb,
+                            offset + offsetof(struct fmip6_opt_hdr, fmip6_opt_optcode), 1, "Option-Code: %s",
+                            val_to_str(opt->fmip6_opt_optcode, names_fmip6_ip_addr_opt_code, "Unknown"));
+
+        proto_tree_add_text(icmp6opt_tree, tvb,
+                            offset + offsetof(struct fmip6_opt_ip_address, fmip6_opt_prefix_len),
+                            1, "Prefix length: %u", opt_ip->fmip6_opt_prefix_len);
+
+        proto_tree_add_text(icmp6opt_tree, tvb,
+                            offset + offsetof(struct fmip6_opt_ip_address, fmip6_opt_ip6_address),
+                            16, "IPv6 Address: %s",
+                            ip6_to_str(&opt_ip->fmip6_opt_ip6_address));
+        break;
+    }
+    case FMIP6_OPT_NEW_ROUTER_PREFIX_INFO:
+    {
+        struct fmip6_opt_new_router_prefix_info fmip6_opt_new_router_prefix_info, *opt_nr;
+
+        opt_nr = &fmip6_opt_new_router_prefix_info;
+        tvb_memcpy(tvb, (guint8 *)opt_nr, offset, sizeof *opt_nr);
+
+        proto_tree_add_text(icmp6opt_tree, tvb,
+                            offset + offsetof(struct fmip6_opt_hdr, fmip6_opt_optcode), 1, "Option-Code: %u",
+                            opt->fmip6_opt_optcode);
+
+        proto_tree_add_text(icmp6opt_tree, tvb,
+                            offset + offsetof(struct fmip6_opt_new_router_prefix_info, fmip6_opt_prefix_len),
+                            1, "Prefix length: %u", opt_nr->fmip6_opt_prefix_len);
+
+        proto_tree_add_text(icmp6opt_tree, tvb,
+                            offset + offsetof(struct fmip6_opt_new_router_prefix_info, fmip6_opt_prefix),
+                            16, "Prefix: %s",
+                            ip6_to_str(&opt_nr->fmip6_opt_prefix));
+        break;
+    }
+    case FMIP6_OPT_LINK_LAYER_ADDRESS:
+    {
+        int len_local, p;
+
+        p = offset + sizeof(*opt);
+        proto_tree_add_text(icmp6opt_tree, tvb,
+                            offset + offsetof(struct fmip6_opt_hdr, fmip6_opt_optcode), 1, "Option-Code: %s",
+                            val_to_str(opt->fmip6_opt_optcode, names_fmip6_lla_opt_code, "Unknown"));
+        len_local = (opt->fmip6_opt_len << 3) - sizeof(*opt);
+        proto_tree_add_text(icmp6opt_tree, tvb,
+                            offset + sizeof(*opt), len_local, "Link-layer address: %s",
+                            bytestring_to_str(tvb_get_ptr(tvb, p, len_local), len_local, ':'));
+        break;
+    }
+    } /* switch (opt->fmip6_opt_type) */
+
+    offset += (opt->fmip6_opt_len << 3);
+    goto again;
 }
 
 /*
@@ -849,82 +923,63 @@ again:
  * Note that the packet format was changed several times in the past.
  */
 
-static const char *
-bitrange0(guint32 v, int s, char *buf, int buflen)
+static void
+bitrange0(guint32 v, int s, emem_strbuf_t *strbuf)
 {
-       guint32 v0;
-       char *p, *ep;
-       int off;
-       int i, l;
-
-       if (buflen < 1)
-               return NULL;
-       if (buflen == 1) {
-               buf[0] = '\0';
-               return NULL;
-       }
-
-       v0 = v;
-       p = buf;
-       ep = buf + buflen - 1;
-       memset(buf, 0, buflen);
-       off = 0;
-       while (off < 32) {
-               /* shift till we have 0x01 */
-               if ((v & 0x01) == 0) {
-                       switch (v & 0x0f) {
-                       case 0x00:
-                               v >>= 4; off += 4; continue;
-                       case 0x08:
-                               v >>= 3; off += 3; continue;
-                       case 0x04: case 0x0c:
-                               v >>= 2; off += 2; continue;
-                       default:
-                               v >>= 1; off += 1; continue;
-                       }
-               }
-
-               /* we have 0x01 with us */
-               for (i = 0; i < 32 - off; i++) {
-                       if ((v & (0x01 << i)) == 0)
-                               break;
-               }
-               if (i == 1)
-                       l = g_snprintf(p, ep - p, ",%d", s + off);
-               else {
-                       l = g_snprintf(p, ep - p, ",%d-%d", s + off,
-                           s + off + i - 1);
-               }
-               if (l == -1 || l >= ep - p) {
-                       return NULL;
-               }
-               v >>= i; off += i;
-       }
-
-       return buf;
+    guint32 v0;
+    int off;
+    int i;
+
+    v0 = v;
+    off = 0;
+    while (off < 32) {
+        /* shift till we have 0x01 */
+        if ((v & 0x01) == 0) {
+            switch (v & 0x0f) {
+            case 0x00:
+                v >>= 4; off += 4; continue;
+            case 0x08:
+                v >>= 3; off += 3; continue;
+            case 0x04: case 0x0c:
+                v >>= 2; off += 2; continue;
+            default:
+                v >>= 1; off += 1; continue;
+            }
+        }
+
+        /* we have 0x01 with us */
+        for (i = 0; i < 32 - off; i++) {
+            if ((v & (0x01 << i)) == 0)
+                break;
+        }
+        if (i == 1)
+            ep_strbuf_append_printf(strbuf, ",%d", s + off);
+        else {
+            ep_strbuf_append_printf(strbuf, ",%d-%d", s + off,
+                                    s + off + i - 1);
+        }
+        v >>= i; off += i;
+    }
 }
 
 static const char *
 bitrange(tvbuff_t *tvb, int offset, int l, int s)
 {
-    static char buf[1024];
-    char *q, *eq;
+    emem_strbuf_t *strbuf;
     int i;
 
-    memset(buf, 0, sizeof(buf));
-    q = buf;
-    eq = buf + sizeof(buf) - 1;
-    for (i = 0; i < l; i++) {
-       if (bitrange0(tvb_get_ntohl(tvb, offset + i * 4), s + i * 4, q, eq - q) == NULL) {
-           if (q != buf && q + 5 < buf + sizeof(buf))
-               g_strlcpy(q, ",...", 5);
-           return buf;
-       }
-    }
+    strbuf = ep_strbuf_new_label(NULL);
+    for (i = 0; i < l; i++)
+        bitrange0(tvb_get_ntohl(tvb, offset + i * 4), s + i * 4, strbuf);
 
-    return buf + 1;
+    return strbuf->str + 1;     /* skip initial "," */
 }
 
+#define NI_SIZE 16
+#define NI_FLAGS_SIZE 2
+#define NI_FLAGS_OFFSET 6
+#define NI_NONCE_SIZE 8
+#define NI_NONCE_OFFSET 8
 static void
 dissect_nodeinfo(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
 {
@@ -935,7 +990,7 @@ dissect_nodeinfo(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree
     unsigned int j;
     int i, n, l, p;
     guint16 flags;
-    const char *dname;
+    const guchar *dname;
     guint32 ipaddr;
 
     ni = &icmp6_nodeinfo;
@@ -943,248 +998,255 @@ dissect_nodeinfo(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree
     /* flags */
     flags = pntohs(&ni->ni_flags);
     tf = proto_tree_add_text(tree, tvb,
-       offset + offsetof(struct icmp6_nodeinfo, ni_flags),
-       sizeof(ni->ni_flags), "Flags: 0x%04x", flags);
+                             offset + NI_FLAGS_OFFSET,
+                             NI_FLAGS_SIZE, "Flags: 0x%04x", flags);
     field_tree = proto_item_add_subtree(tf, ett_nodeinfo_flag);
     switch (pntohs(&ni->ni_qtype)) {
     case NI_QTYPE_SUPTYPES:
-       if (ni->ni_type == ICMP6_NI_QUERY) {
-           proto_tree_add_text(field_tree, tvb,
-               offset + offsetof(struct icmp6_nodeinfo, ni_flags),
-               sizeof(ni->ni_flags), "%s",
-               decode_boolean_bitfield(flags, NI_SUPTYPE_FLAG_COMPRESS, sizeof(flags) * 8,
-                   "Compressed reply supported",
-                   "No compressed reply support"));
-       } else {
-           proto_tree_add_text(field_tree, tvb,
-               offset + offsetof(struct icmp6_nodeinfo, ni_flags),
-               sizeof(ni->ni_flags), "%s",
-               decode_boolean_bitfield(flags, NI_SUPTYPE_FLAG_COMPRESS, sizeof(flags) * 8,
-                   "Compressed", "Not compressed"));
-       }
-       break;
+        if (ni->ni_type == ICMP6_NI_QUERY) {
+            proto_tree_add_text(field_tree, tvb,
+                                offset + NI_FLAGS_OFFSET,
+                                NI_FLAGS_SIZE, "%s",
+                                decode_boolean_bitfield(flags, NI_SUPTYPE_FLAG_COMPRESS, sizeof(flags) * 8,
+                                                        "Compressed reply supported",
+                                                        "No compressed reply support"));
+        } else {
+            proto_tree_add_text(field_tree, tvb,
+                                offset + NI_FLAGS_OFFSET,
+                                NI_FLAGS_SIZE, "%s",
+                                decode_boolean_bitfield(flags, NI_SUPTYPE_FLAG_COMPRESS, sizeof(flags) * 8,
+                                                        "Compressed", "Not compressed"));
+        }
+        break;
     case NI_QTYPE_DNSNAME:
-       if (ni->ni_type == ICMP6_NI_REPLY) {
-           proto_tree_add_text(field_tree, tvb,
-               offset + offsetof(struct icmp6_nodeinfo, ni_flags),
-               sizeof(ni->ni_flags), "%s",
-               decode_boolean_bitfield(flags, NI_FQDN_FLAG_VALIDTTL, sizeof(flags) * 8,
-                   "Valid TTL field", "Meaningless TTL field"));
-       }
-       break;
+        if (ni->ni_type == ICMP6_NI_REPLY) {
+            proto_tree_add_text(field_tree, tvb,
+                                offset + NI_FLAGS_OFFSET,
+                                NI_FLAGS_SIZE, "%s",
+                                decode_boolean_bitfield(flags, NI_FQDN_FLAG_VALIDTTL, sizeof(flags) * 8,
+                                                        "Valid TTL field", "Meaningless TTL field"));
+        }
+        break;
     case NI_QTYPE_NODEADDR:
-       proto_tree_add_text(field_tree, tvb,
-           offset + offsetof(struct icmp6_nodeinfo, ni_flags),
-           sizeof(ni->ni_flags), "%s",
-           decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_GLOBAL, sizeof(flags) * 8,
-               "Global address",
-               "Not global address"));
-       proto_tree_add_text(field_tree, tvb,
-           offset + offsetof(struct icmp6_nodeinfo, ni_flags),
-           sizeof(ni->ni_flags), "%s",
-           decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_SITELOCAL, sizeof(flags) * 8,
-               "Site-local address",
-               "Not site-local address"));
-       proto_tree_add_text(field_tree, tvb,
-           offset + offsetof(struct icmp6_nodeinfo, ni_flags),
-           sizeof(ni->ni_flags), "%s",
-           decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_LINKLOCAL, sizeof(flags) * 8,
-               "Link-local address",
-               "Not link-local address"));
-       proto_tree_add_text(field_tree, tvb,
-           offset + offsetof(struct icmp6_nodeinfo, ni_flags),
-           sizeof(ni->ni_flags), "%s",
-           decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_COMPAT, sizeof(flags) * 8,
-               "IPv4 compatible/mapped address",
-               "Not IPv4 compatible/mapped address"));
-       /* fall through */
+        proto_tree_add_text(field_tree, tvb,
+                            offset + NI_FLAGS_OFFSET,
+                            NI_FLAGS_SIZE, "%s",
+                            decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_GLOBAL, sizeof(flags) * 8,
+                                                    "Global address",
+                                                    "Not global address"));
+        proto_tree_add_text(field_tree, tvb,
+                            offset + NI_FLAGS_OFFSET,
+                            NI_FLAGS_SIZE, "%s",
+                            decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_SITELOCAL, sizeof(flags) * 8,
+                                                    "Site-local address",
+                                                    "Not site-local address"));
+        proto_tree_add_text(field_tree, tvb,
+                            offset + NI_FLAGS_OFFSET,
+                            NI_FLAGS_SIZE, "%s",
+                            decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_LINKLOCAL, sizeof(flags) * 8,
+                                                    "Link-local address",
+                                                    "Not link-local address"));
+        proto_tree_add_text(field_tree, tvb,
+                            offset + NI_FLAGS_OFFSET,
+                            NI_FLAGS_SIZE, "%s",
+                            decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_COMPAT, sizeof(flags) * 8,
+                                                    "IPv4 compatible/mapped address",
+                                                    "Not IPv4 compatible/mapped address"));
+        /* fall through */
     case NI_QTYPE_IPV4ADDR:
-       proto_tree_add_text(field_tree, tvb,
-           offset + offsetof(struct icmp6_nodeinfo, ni_flags),
-           sizeof(ni->ni_flags), "%s",
-           decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_ALL, sizeof(flags) * 8,
-               "All unicast address",
-               "Unicast addresses on the queried interface"));
-       proto_tree_add_text(field_tree, tvb,
-           offset + offsetof(struct icmp6_nodeinfo, ni_flags),
-           sizeof(ni->ni_flags), "%s",
-           decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_TRUNCATE, sizeof(flags) * 8,
-               "Truncated", "Not truncated"));
-       break;
-    }
+        proto_tree_add_text(field_tree, tvb,
+                            offset + NI_FLAGS_OFFSET,
+                            NI_FLAGS_SIZE, "%s",
+                            decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_ALL, sizeof(flags) * 8,
+                                                    "All unicast address",
+                                                    "Unicast addresses on the queried interface"));
+        proto_tree_add_text(field_tree, tvb,
+                            offset + NI_FLAGS_OFFSET,
+                            NI_FLAGS_SIZE, "%s",
+                            decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_TRUNCATE, sizeof(flags) * 8,
+                                                    "Truncated", "Not truncated"));
+        break;
+    } /* switch (pntohs(&ni->ni_qtype)) */
 
     /* nonce */
     proto_tree_add_text(tree, tvb,
-       offset + offsetof(struct icmp6_nodeinfo, icmp6_ni_nonce[0]),
-       sizeof(ni->icmp6_ni_nonce), "Nonce: 0x%08x%08x",
-       pntohl(&ni->icmp6_ni_nonce[0]), pntohl(&ni->icmp6_ni_nonce[4]));
+                        offset + NI_NONCE_OFFSET,
+                        NI_NONCE_SIZE, "Nonce: 0x%08x%08x",
+                        pntohl(&ni->icmp6_ni_nonce[0]), pntohl(&ni->icmp6_ni_nonce[4]));
 
     /* offset for "the rest of data" */
-    off = sizeof(*ni);
+    off = NI_SIZE;
 
     /* rest of data */
     if (!tvb_bytes_exist(tvb, offset, sizeof(*ni)))
-       goto nodata;
+        goto nodata;
     if (ni->ni_type == ICMP6_NI_QUERY) {
-       switch (ni->ni_code) {
-       case ICMP6_NI_SUBJ_IPV6:
-           n = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
-           n /= sizeof(struct e_in6_addr);
-           tf = proto_tree_add_text(tree, tvb,
-               offset + sizeof(*ni), -1, "IPv6 subject addresses");
-           field_tree = proto_item_add_subtree(tf, ett_nodeinfo_subject6);
-           p = offset + sizeof *ni;
-           for (i = 0; i < n; i++) {
-               struct e_in6_addr e_in6_addr;
-               tvb_get_ipv6(tvb, p, &e_in6_addr);
-               proto_tree_add_text(field_tree, tvb,
-                   p, sizeof(struct e_in6_addr),
-                   "%s", ip6_to_str(&e_in6_addr));
-               p += sizeof(struct e_in6_addr);
-           }
-           off = tvb_length_remaining(tvb, offset);
-           break;
-       case ICMP6_NI_SUBJ_FQDN:
-           /* XXX Fix data length */
-           l = get_dns_name(tvb, offset + sizeof(*ni), 0,
-               offset + sizeof(*ni), &dname);
-           if (tvb_bytes_exist(tvb, offset + sizeof(*ni) + l, 1) &&
-               tvb_get_guint8(tvb, offset + sizeof(*ni) + l) == 0) {
-               l++;
-               proto_tree_add_text(tree, tvb, offset + sizeof(*ni), l,
-                   "DNS label: %s (truncated)", dname);
-           } else {
-               proto_tree_add_text(tree, tvb, offset + sizeof(*ni), l,
-                   "DNS label: %s", dname);
-           }
-           off = tvb_length_remaining(tvb, offset + sizeof(*ni) + l);
-           break;
-       case ICMP6_NI_SUBJ_IPV4:
-           n = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
-           n /= sizeof(guint32);
-           tf = proto_tree_add_text(tree, tvb,
-               offset + sizeof(*ni), -1, "IPv4 subject addresses");
-           field_tree = proto_item_add_subtree(tf, ett_nodeinfo_subject4);
-           p = offset + sizeof *ni;
-           for (i = 0; i < n; i++) {
-               ipaddr = tvb_get_ipv4(tvb, p);
-               proto_tree_add_text(field_tree, tvb,
-                   p, sizeof(guint32), "%s", ip_to_str((guint8 *)&ipaddr));
-               p += sizeof(guint32);
-           }
-           off = tvb_length_remaining(tvb, offset);
-           break;
-       }
+        switch (ni->ni_code) {
+        case ICMP6_NI_SUBJ_IPV6:
+            n = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
+            n /= sizeof(struct e_in6_addr);
+            tf = proto_tree_add_text(tree, tvb,
+                                     offset + sizeof(*ni), -1, "IPv6 subject addresses");
+            field_tree = proto_item_add_subtree(tf, ett_nodeinfo_subject6);
+            p = offset + sizeof *ni;
+            for (i = 0; i < n; i++) {
+                struct e_in6_addr e_in6_addr;
+                tvb_get_ipv6(tvb, p, &e_in6_addr);
+                proto_tree_add_text(field_tree, tvb,
+                                    p, sizeof(struct e_in6_addr),
+                                    "%s", ip6_to_str(&e_in6_addr));
+                p += sizeof(struct e_in6_addr);
+            }
+            off = tvb_length_remaining(tvb, offset);
+            break;
+        case ICMP6_NI_SUBJ_FQDN:
+            /* XXX Fix data length */
+            l = get_dns_name(tvb, offset + sizeof(*ni), 0,
+                             offset + sizeof(*ni), &dname);
+            if (tvb_bytes_exist(tvb, offset + sizeof(*ni) + l, 1) &&
+                tvb_get_guint8(tvb, offset + sizeof(*ni) + l) == 0) {
+                l++;
+                proto_tree_add_text(tree, tvb, offset + sizeof(*ni), l,
+                                    "DNS label: %s (truncated)", dname);
+            } else {
+                proto_tree_add_text(tree, tvb, offset + sizeof(*ni), l,
+                                    "DNS label: %s", dname);
+            }
+            off = tvb_length_remaining(tvb, offset + sizeof(*ni) + l);
+            break;
+        case ICMP6_NI_SUBJ_IPV4:
+            n = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
+            n /= sizeof(guint32);
+            tf = proto_tree_add_text(tree, tvb,
+                                     offset + sizeof(*ni), -1, "IPv4 subject addresses");
+            field_tree = proto_item_add_subtree(tf, ett_nodeinfo_subject4);
+            p = offset + sizeof *ni;
+            for (i = 0; i < n; i++) {
+                ipaddr = tvb_get_ipv4(tvb, p);
+                proto_tree_add_text(field_tree, tvb,
+                                    p, sizeof(guint32), "%s", ip_to_str((guint8 *)&ipaddr));
+                p += sizeof(guint32);
+            }
+            off = tvb_length_remaining(tvb, offset);
+            break;
+        } /* switch (ni->ni_code) */
     } else {
-       switch (pntohs(&ni->ni_qtype)) {
-       case NI_QTYPE_NOOP:
-           break;
-       case NI_QTYPE_SUPTYPES:
-           p = offset + sizeof *ni;
-           tf = proto_tree_add_text(tree, tvb,
-               offset + sizeof(*ni), -1,
-               "Supported type bitmap%s",
-               (flags & 0x0001) ? ", compressed" : "");
-           field_tree = proto_item_add_subtree(tf,
-               ett_nodeinfo_nodebitmap);
-           n = 0;
-           while (tvb_bytes_exist(tvb, p, sizeof(guint32))) { /* XXXX Check what? */
-               if ((flags & 0x0001) == 0) {
-                   l = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
-                   l /= sizeof(guint32);
-                   i = 0;
-               } else {
-                   l = tvb_get_ntohs(tvb, p);
-                   i = tvb_get_ntohs(tvb, p + sizeof(guint16));        /*skip*/
-               }
-               if (n + l * 32 > (1 << 16))
-                   break;
-               if (n + (l + i) * 32 > (1 << 16))
-                   break;
-               if ((flags & 0x0001) == 0) {
-                   proto_tree_add_text(field_tree, tvb, p,
-                       l * 4, "Bitmap (%d to %d): %s", n, n + l * 32 - 1,
-                       bitrange(tvb, p, l, n));
-                   p += l * 4;
-               } else {
-                   proto_tree_add_text(field_tree, tvb, p,
-                       4 + l * 4, "Bitmap (%d to %d): %s", n, n + l * 32 - 1,
-                       bitrange(tvb, p + 4, l, n));
-                   p += (4 + l * 4);
-               }
-               n += l * 32 + i * 32;
-           }
-           off = tvb_length_remaining(tvb, offset);
-           break;
-       case NI_QTYPE_DNSNAME:
-           proto_tree_add_text(tree, tvb, offset + sizeof(*ni),
-               sizeof(gint32), "TTL: %d", (gint32)tvb_get_ntohl(tvb, offset + sizeof *ni));
-           tf = proto_tree_add_text(tree, tvb,
-               offset + sizeof(*ni) + sizeof(guint32), -1,
-               "DNS labels");
-           field_tree = proto_item_add_subtree(tf, ett_nodeinfo_nodedns);
-           j = offset + sizeof (*ni) + sizeof(guint32);
-           while (j < tvb_reported_length(tvb)) {
-               /* XXX Fix data length */
-               l = get_dns_name(tvb, j, 0,
-                  offset + sizeof (*ni) + sizeof(guint32),
-                  &dname);
-               if (tvb_bytes_exist(tvb, j + l, 1) &&
-                   tvb_get_guint8(tvb, j + l) == 0) {
-                   l++;
-                   proto_tree_add_text(field_tree, tvb, j, l,
-                       "DNS label: %s (truncated)", dname);
-               } else {
-                   proto_tree_add_text(field_tree, tvb, j, l,
-                       "DNS label: %s", dname);
-               }
-               j += l;
-           }
-           off = tvb_length_remaining(tvb, offset);
-           break;
-       case NI_QTYPE_NODEADDR:
-           n = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
-           n /= sizeof(gint32) + sizeof(struct e_in6_addr);
-           tf = proto_tree_add_text(tree, tvb,
-               offset + sizeof(*ni), -1, "IPv6 node addresses");
-           field_tree = proto_item_add_subtree(tf, ett_nodeinfo_node6);
-           p = offset + sizeof (*ni);
-           for (i = 0; i < n; i++) {
-               struct e_in6_addr e_in6_addr;
-               gint32 ttl;
-               ttl = (gint32)tvb_get_ntohl(tvb, p);
-               tvb_get_ipv6(tvb, p + sizeof ttl, &e_in6_addr);
-               proto_tree_add_text(field_tree, tvb,
-                   p, sizeof(struct e_in6_addr) + sizeof(gint32),
-                   "%s (TTL %d)", ip6_to_str(&e_in6_addr), ttl);
-               p += sizeof(struct e_in6_addr) + sizeof(gint32);
-           }
-           off = tvb_length_remaining(tvb, offset);
-           break;
-       case NI_QTYPE_IPV4ADDR:
-           n = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
-           n /= sizeof(gint32) + sizeof(guint32);
-           tf = proto_tree_add_text(tree, tvb,
-               offset + sizeof(*ni), -1, "IPv4 node addresses");
-           field_tree = proto_item_add_subtree(tf, ett_nodeinfo_node4);
-           p = offset + sizeof *ni;
-           for (i = 0; i < n; i++) {
-               ipaddr = tvb_get_ipv4(tvb, sizeof(gint32) + p);
-               proto_tree_add_text(field_tree, tvb,
-                   p, sizeof(guint32), "%s (TTL %d)",
-                   ip_to_str((guint8 *)&ipaddr), tvb_get_ntohl(tvb, p));
-               p += sizeof(gint32) + sizeof(guint32);
-           }
-           off = tvb_length_remaining(tvb, offset);
-           break;
-       }
+        switch (pntohs(&ni->ni_qtype)) {
+        case NI_QTYPE_NOOP:
+            break;
+        case NI_QTYPE_SUPTYPES:
+            p = offset + sizeof *ni;
+            tf = proto_tree_add_text(tree, tvb,
+                                     offset + sizeof(*ni), -1,
+                                     "Supported type bitmap%s",
+                                     (flags & 0x0001) ? ", compressed" : "");
+            field_tree = proto_item_add_subtree(tf,
+                                                ett_nodeinfo_nodebitmap);
+            n = 0;
+            while (tvb_bytes_exist(tvb, p, sizeof(guint32))) { /* XXXX Check what? */
+                if ((flags & 0x0001) == 0) {
+                    l = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
+                    l /= sizeof(guint32);
+                    i = 0;
+                } else {
+                    l = tvb_get_ntohs(tvb, p);
+                    i = tvb_get_ntohs(tvb, p + sizeof(guint16));        /*skip*/
+                }
+                if (n + l * 32 > (1 << 16))
+                    break;
+                if (n + (l + i) * 32 > (1 << 16))
+                    break;
+                if ((flags & 0x0001) == 0) {
+                    proto_tree_add_text(field_tree, tvb, p,
+                                        l * 4, "Bitmap (%d to %d): %s", n, n + l * 32 - 1,
+                                        bitrange(tvb, p, l, n));
+                    p += l * 4;
+                } else {
+                    proto_tree_add_text(field_tree, tvb, p,
+                                        4 + l * 4, "Bitmap (%d to %d): %s", n, n + l * 32 - 1,
+                                        bitrange(tvb, p + 4, l, n));
+                    p += (4 + l * 4);
+                }
+                n += l * 32 + i * 32;
+            }
+            off = tvb_length_remaining(tvb, offset);
+            break;
+        case NI_QTYPE_DNSNAME:
+            proto_tree_add_text(tree, tvb, offset + sizeof(*ni),
+                                sizeof(gint32), "TTL: %d", (gint32)tvb_get_ntohl(tvb, offset + sizeof *ni));
+            tf = proto_tree_add_text(tree, tvb,
+                                     offset + sizeof(*ni) + sizeof(guint32),    -1,
+                                     "DNS labels");
+            field_tree = proto_item_add_subtree(tf, ett_nodeinfo_nodedns);
+            j = offset + sizeof (*ni) + sizeof(guint32);
+            while (j < tvb_reported_length(tvb)) {
+                /* XXX Fix data length */
+                l = get_dns_name(tvb, j, 0,
+                                 offset + sizeof (*ni) + sizeof(guint32),
+                                 &dname);
+                if (tvb_bytes_exist(tvb, j + l, 1) &&
+                    tvb_get_guint8(tvb, j + l) == 0) {
+                    l++;
+                    proto_tree_add_text(field_tree, tvb, j, l,
+                                        "DNS label: %s (truncated)", dname);
+                } else {
+                    proto_tree_add_text(field_tree, tvb, j, l,
+                                        "DNS label: %s", dname);
+                }
+                j += l;
+            }
+            off = tvb_length_remaining(tvb, offset);
+            break;
+        case NI_QTYPE_NODEADDR:
+            n = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
+            n /= sizeof(gint32) + sizeof(struct e_in6_addr);
+            tf = proto_tree_add_text(tree, tvb,
+                                     offset + sizeof(*ni), -1, "IPv6 node addresses");
+            field_tree = proto_item_add_subtree(tf, ett_nodeinfo_node6);
+            p = offset + sizeof (*ni);
+            for (i = 0; i < n; i++) {
+                struct e_in6_addr e_in6_addr;
+                gint32 ttl;
+                ttl = (gint32)tvb_get_ntohl(tvb, p);
+                tvb_get_ipv6(tvb, p + sizeof ttl, &e_in6_addr);
+                proto_tree_add_text(field_tree, tvb,
+                                    p, sizeof(struct e_in6_addr) + sizeof(gint32),
+                                    "%s (TTL %d)", ip6_to_str(&e_in6_addr), ttl);
+                p += sizeof(struct e_in6_addr) + sizeof(gint32);
+            }
+            off = tvb_length_remaining(tvb, offset);
+            break;
+        case NI_QTYPE_IPV4ADDR:
+            n = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
+            n /= sizeof(gint32) + sizeof(guint32);
+            tf = proto_tree_add_text(tree, tvb,
+                                     offset + sizeof(*ni), -1, "IPv4 node addresses");
+            field_tree = proto_item_add_subtree(tf, ett_nodeinfo_node4);
+            p = offset + sizeof *ni;
+            for (i = 0; i < n; i++) {
+                ipaddr = tvb_get_ipv4(tvb, sizeof(gint32) + p);
+                proto_tree_add_text(field_tree, tvb,
+                                    p, sizeof(guint32), "%s (TTL %d)",
+                                    ip_to_str((guint8 *)&ipaddr), tvb_get_ntohl(tvb, p));
+                p += sizeof(gint32) + sizeof(guint32);
+            }
+            off = tvb_length_remaining(tvb, offset);
+            break;
+        } /* switch (pntohs(&ni->ni_qtype)) */
     }
 nodata:;
 
     /* the rest of data */
-    call_dissector(data_handle,tvb_new_subset(tvb, offset + off, -1, -1), pinfo, tree);
+    call_dissector(data_handle,tvb_new_subset_remaining(tvb, offset + off), pinfo, tree);
 }
 
+#define RR_SIZE 16
+#define RR_SEQNUM_SIZE 4
+#define RR_SEQNUM_OFFSET 4
+#define RR_SEGNUM_SIZE 1
+#define RR_SEGNUM_OFFSET 8
+#define RR_FLAGS_SIZE 1
+#define RR_FLAGS_OFFSET 9
 static void
 dissect_rrenum(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
 {
@@ -1200,150 +1262,150 @@ dissect_rrenum(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
     rr = &icmp6_router_renum;
     tvb_memcpy(tvb, (guint8 *)rr, offset, sizeof *rr);
     proto_tree_add_text(tree, tvb,
-       offset + offsetof(struct icmp6_router_renum, rr_seqnum), 4,
-       "Sequence number: 0x%08x", pntohl(&rr->rr_seqnum));
+                        offset + RR_SEQNUM_OFFSET, RR_SEQNUM_SIZE,
+                        "Sequence number: 0x%08x", pntohl(&rr->rr_seqnum));
     proto_tree_add_text(tree, tvb,
-       offset + offsetof(struct icmp6_router_renum, rr_segnum), 1,
-       "Segment number: 0x%02x", rr->rr_segnum);
+                        offset + RR_SEGNUM_OFFSET, RR_SEGNUM_SIZE,
+                        "Segment number: 0x%02x", rr->rr_segnum);
 
-    flagoff = offset + offsetof(struct icmp6_router_renum, rr_flags);
+    flagoff = offset + RR_FLAGS_OFFSET;
     flags = tvb_get_guint8(tvb, flagoff);
-    tf = proto_tree_add_text(tree, tvb, flagoff, 1,
-       "Flags: 0x%02x", flags);
+    tf = proto_tree_add_text(tree, tvb, flagoff, RR_FLAGS_SIZE,
+                             "Flags: 0x%02x", flags);
     field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
-    proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
-       decode_boolean_bitfield(flags, 0x80, 8,
-           "Test command", "Not test command"));
-    proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
-       decode_boolean_bitfield(flags, 0x40, 8,
-           "Result requested", "Result not requested"));
-    proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
-       decode_boolean_bitfield(flags, 0x20, 8,
-           "All interfaces", "Not all interfaces"));
-    proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
-       decode_boolean_bitfield(flags, 0x10, 8,
-           "Site specific", "Not site specific"));
-    proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
-       decode_boolean_bitfield(flags, 0x08, 8,
-           "Processed previously", "Complete result"));
+    proto_tree_add_text(field_tree, tvb, flagoff, RR_FLAGS_SIZE, "%s",
+                        decode_boolean_bitfield(flags, 0x80, 8,
+                                                "Test command", "Not test command"));
+    proto_tree_add_text(field_tree, tvb, flagoff, RR_FLAGS_SIZE, "%s",
+                        decode_boolean_bitfield(flags, 0x40, 8,
+                                                "Result requested", "Result not requested"));
+    proto_tree_add_text(field_tree, tvb, flagoff, RR_FLAGS_SIZE, "%s",
+                        decode_boolean_bitfield(flags, 0x20, 8,
+                                                "All interfaces", "Not all interfaces"));
+    proto_tree_add_text(field_tree, tvb, flagoff, RR_FLAGS_SIZE, "%s",
+                        decode_boolean_bitfield(flags, 0x10, 8,
+                                                "Site specific", "Not site specific"));
+    proto_tree_add_text(field_tree, tvb, flagoff, RR_FLAGS_SIZE, "%s",
+                        decode_boolean_bitfield(flags, 0x08, 8,
+                                                "Processed previously", "Complete result"));
 
     proto_tree_add_text(tree, tvb,
-       offset + offsetof(struct icmp6_router_renum, rr_maxdelay), 2,
-       "Max delay: 0x%04x", pntohs(&rr->rr_maxdelay));
-    call_dissector(data_handle,tvb_new_subset(tvb, offset + sizeof(*rr), -1, -1), pinfo, tree);        /*XXX*/
+                        offset + offsetof(struct icmp6_router_renum, rr_maxdelay), 2,
+                        "Max delay: 0x%04x", pntohs(&rr->rr_maxdelay));
+    call_dissector(data_handle,tvb_new_subset_remaining(tvb, offset + RR_SIZE), pinfo, tree);   /*XXX*/
 
     if (rr->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) {
-       off = offset + sizeof(*rr);
-       match = &rr_pco_match;
-       tvb_memcpy(tvb, (guint8 *)match, off, sizeof *match);
-       tf = proto_tree_add_text(tree, tvb, off, sizeof(*match),
-           "Match-Prefix: %s/%u (%u-%u)", ip6_to_str(&match->rpm_prefix),
-           match->rpm_matchlen, match->rpm_minlen, match->rpm_maxlen);
-       opt_tree = proto_item_add_subtree(tf, ett_icmpv6opt);
-       proto_tree_add_text(opt_tree, tvb,
-           off + offsetof(struct rr_pco_match, rpm_code),
-           sizeof(match->rpm_code), "OpCode: %s (%u)",
-           val_to_str(match->rpm_code, names_rrenum_matchcode, "Unknown"),
-           match->rpm_code);
-       proto_tree_add_text(opt_tree, tvb,
-           off + offsetof(struct rr_pco_match, rpm_len),
-           sizeof(match->rpm_len), "OpLength: %u (%u octets)",
-           match->rpm_len, match->rpm_len * 8);
-       proto_tree_add_text(opt_tree, tvb,
-           off + offsetof(struct rr_pco_match, rpm_ordinal),
-           sizeof(match->rpm_ordinal), "Ordinal: %u", match->rpm_ordinal);
-       proto_tree_add_text(opt_tree, tvb,
-           off + offsetof(struct rr_pco_match, rpm_matchlen),
-           sizeof(match->rpm_matchlen), "MatchLen: %u", match->rpm_matchlen);
-       proto_tree_add_text(opt_tree, tvb,
-           off + offsetof(struct rr_pco_match, rpm_minlen),
-           sizeof(match->rpm_minlen), "MinLen: %u", match->rpm_minlen);
-       proto_tree_add_text(opt_tree, tvb,
-           off + offsetof(struct rr_pco_match, rpm_maxlen),
-           sizeof(match->rpm_maxlen), "MaxLen: %u", match->rpm_maxlen);
-       proto_tree_add_text(opt_tree, tvb,
-           off + offsetof(struct rr_pco_match, rpm_prefix),
-           sizeof(match->rpm_prefix), "MatchPrefix: %s",
-           ip6_to_str(&match->rpm_prefix));
-
-       off += sizeof(*match);
-       use = &rr_pco_use;
-       for (l = match->rpm_len * 8 - sizeof(*match);
-            l >= sizeof(*use); l -= sizeof(*use), off += sizeof(*use)) {
-           tvb_memcpy(tvb, (guint8 *)use, off, sizeof *use);
-           tf = proto_tree_add_text(tree, tvb, off, sizeof(*use),
-               "Use-Prefix: %s/%u (keep %u)", ip6_to_str(&use->rpu_prefix),
-               use->rpu_uselen, use->rpu_keeplen);
-           opt_tree = proto_item_add_subtree(tf, ett_icmpv6opt);
-           proto_tree_add_text(opt_tree, tvb,
-               off + offsetof(struct rr_pco_use, rpu_uselen),
-               sizeof(use->rpu_uselen), "UseLen: %u", use->rpu_uselen);
-           proto_tree_add_text(opt_tree, tvb,
-               off + offsetof(struct rr_pco_use, rpu_keeplen),
-               sizeof(use->rpu_keeplen), "KeepLen: %u", use->rpu_keeplen);
-           tf = proto_tree_add_text(opt_tree, tvb,
-               flagoff = off + offsetof(struct rr_pco_use, rpu_ramask),
-               sizeof(use->rpu_ramask), "FlagMask: 0x%x", use->rpu_ramask);
-           field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
-           flags = tvb_get_guint8(tvb, flagoff);
-           proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
-               decode_boolean_bitfield(flags,
-                   ICMP6_RR_PCOUSE_RAFLAGS_ONLINK, 8,
-                   "Onlink", "Not onlink"));
-           proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
-               decode_boolean_bitfield(flags,
-                   ICMP6_RR_PCOUSE_RAFLAGS_AUTO, 8,
-                   "Auto", "Not auto"));
-           tf = proto_tree_add_text(opt_tree, tvb,
-               flagoff = off + offsetof(struct rr_pco_use, rpu_raflags),
-               sizeof(use->rpu_raflags), "RAFlags: 0x%x", use->rpu_raflags);
-           field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
-           flags = tvb_get_guint8(tvb, flagoff);
-           proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
-               decode_boolean_bitfield(flags,
-                   ICMP6_RR_PCOUSE_RAFLAGS_ONLINK, 8,
-                   "Onlink", "Not onlink"));
-           proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
-               decode_boolean_bitfield(flags,
-                   ICMP6_RR_PCOUSE_RAFLAGS_AUTO, 8, "Auto", "Not auto"));
-           if (pntohl(&use->rpu_vltime) == 0xffffffff)
-               proto_tree_add_text(opt_tree, tvb,
-                   off + offsetof(struct rr_pco_use, rpu_vltime),
-                   sizeof(use->rpu_vltime), "Valid Lifetime: infinity");
-           else
-               proto_tree_add_text(opt_tree, tvb,
-                   off + offsetof(struct rr_pco_use, rpu_vltime),
-                   sizeof(use->rpu_vltime), "Valid Lifetime: %u",
-                   pntohl(&use->rpu_vltime));
-           if (pntohl(&use->rpu_pltime) == 0xffffffff)
-               proto_tree_add_text(opt_tree, tvb,
-                   off + offsetof(struct rr_pco_use, rpu_pltime),
-                   sizeof(use->rpu_pltime), "Preferred Lifetime: infinity");
-           else
-               proto_tree_add_text(opt_tree, tvb,
-                   off + offsetof(struct rr_pco_use, rpu_pltime),
-                   sizeof(use->rpu_pltime), "Preferred Lifetime: %u",
-                   pntohl(&use->rpu_pltime));
-           tf = proto_tree_add_text(opt_tree, tvb,
-               flagoff = off + offsetof(struct rr_pco_use, rpu_flags),
-               sizeof(use->rpu_flags), "Flags: 0x%08x",
-               pntohl(&use->rpu_flags));
-           field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
-           flags = tvb_get_guint8(tvb, flagoff);
-           proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
-               decode_boolean_bitfield(flags,
-                   ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, 32,
-                   "Decrement valid lifetime", "No decrement valid lifetime"));
-           proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
-               decode_boolean_bitfield(flags,
-                   ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, 32,
-                   "Decrement preferred lifetime",
-                   "No decrement preferred lifetime"));
-           proto_tree_add_text(opt_tree, tvb,
-               off + offsetof(struct rr_pco_use, rpu_prefix),
-               sizeof(use->rpu_prefix), "UsePrefix: %s",
-               ip6_to_str(&use->rpu_prefix));
-       }
+        off = offset + RR_SIZE;
+        match = &rr_pco_match;
+        tvb_memcpy(tvb, (guint8 *)match, off, sizeof *match);
+        tf = proto_tree_add_text(tree, tvb, off, sizeof(*match),
+                                 "Match-Prefix: %s/%u (%u-%u)", ip6_to_str(&match->rpm_prefix),
+                                 match->rpm_matchlen, match->rpm_minlen, match->rpm_maxlen);
+        opt_tree = proto_item_add_subtree(tf, ett_icmpv6opt);
+        proto_tree_add_text(opt_tree, tvb,
+                            off + offsetof(struct rr_pco_match, rpm_code),
+                            sizeof(match->rpm_code), "OpCode: %s (%u)",
+                            val_to_str(match->rpm_code, names_rrenum_matchcode, "Unknown"),
+                            match->rpm_code);
+        proto_tree_add_text(opt_tree, tvb,
+                            off + offsetof(struct rr_pco_match, rpm_len),
+                            sizeof(match->rpm_len), "OpLength: %u (%u octets)",
+                            match->rpm_len, match->rpm_len * 8);
+        proto_tree_add_text(opt_tree, tvb,
+                            off + offsetof(struct rr_pco_match, rpm_ordinal),
+                            sizeof(match->rpm_ordinal), "Ordinal: %u", match->rpm_ordinal);
+        proto_tree_add_text(opt_tree, tvb,
+                            off + offsetof(struct rr_pco_match, rpm_matchlen),
+                            sizeof(match->rpm_matchlen), "MatchLen: %u", match->rpm_matchlen);
+        proto_tree_add_text(opt_tree, tvb,
+                            off + offsetof(struct rr_pco_match, rpm_minlen),
+                            sizeof(match->rpm_minlen), "MinLen: %u", match->rpm_minlen);
+        proto_tree_add_text(opt_tree, tvb,
+                            off + offsetof(struct rr_pco_match, rpm_maxlen),
+                            sizeof(match->rpm_maxlen), "MaxLen: %u", match->rpm_maxlen);
+        proto_tree_add_text(opt_tree, tvb,
+                            off + offsetof(struct rr_pco_match, rpm_prefix),
+                            sizeof(match->rpm_prefix), "MatchPrefix: %s",
+                            ip6_to_str(&match->rpm_prefix));
+
+        off += sizeof(*match);
+        use = &rr_pco_use;
+        for (l = match->rpm_len * 8 - sizeof(*match);
+             l >= sizeof(*use); l -= sizeof(*use), off += sizeof(*use)) {
+            tvb_memcpy(tvb, (guint8 *)use, off, sizeof *use);
+            tf = proto_tree_add_text(tree, tvb, off, sizeof(*use),
+                                     "Use-Prefix: %s/%u (keep %u)", ip6_to_str(&use->rpu_prefix),
+                                     use->rpu_uselen, use->rpu_keeplen);
+            opt_tree = proto_item_add_subtree(tf, ett_icmpv6opt);
+            proto_tree_add_text(opt_tree, tvb,
+                                off + offsetof(struct rr_pco_use, rpu_uselen),
+                                sizeof(use->rpu_uselen), "UseLen: %u", use->rpu_uselen);
+            proto_tree_add_text(opt_tree, tvb,
+                                off + offsetof(struct rr_pco_use, rpu_keeplen),
+                                sizeof(use->rpu_keeplen), "KeepLen: %u", use->rpu_keeplen);
+            tf = proto_tree_add_text(opt_tree, tvb,
+                                     flagoff = off + offsetof(struct rr_pco_use, rpu_ramask),
+                                     sizeof(use->rpu_ramask), "FlagMask: 0x%x", use->rpu_ramask);
+            field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
+            flags = tvb_get_guint8(tvb, flagoff);
+            proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
+                                decode_boolean_bitfield(flags,
+                                                        ICMP6_RR_PCOUSE_RAFLAGS_ONLINK, 8,
+                                                        "Onlink", "Not onlink"));
+            proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
+                                decode_boolean_bitfield(flags,
+                                                        ICMP6_RR_PCOUSE_RAFLAGS_AUTO, 8,
+                                                        "Auto", "Not auto"));
+            tf = proto_tree_add_text(opt_tree, tvb,
+                                     flagoff = off + offsetof(struct rr_pco_use, rpu_raflags),
+                                     sizeof(use->rpu_raflags), "RAFlags: 0x%x", use->rpu_raflags);
+            field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
+            flags = tvb_get_guint8(tvb, flagoff);
+            proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
+                                decode_boolean_bitfield(flags,
+                                                        ICMP6_RR_PCOUSE_RAFLAGS_ONLINK, 8,
+                                                        "Onlink", "Not onlink"));
+            proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
+                                decode_boolean_bitfield(flags,
+                                                        ICMP6_RR_PCOUSE_RAFLAGS_AUTO, 8, "Auto", "Not auto"));
+            if (pntohl(&use->rpu_vltime) == 0xffffffff)
+                proto_tree_add_text(opt_tree, tvb,
+                                    off + offsetof(struct rr_pco_use, rpu_vltime),
+                                    sizeof(use->rpu_vltime), "Valid Lifetime: infinity");
+            else
+                proto_tree_add_text(opt_tree, tvb,
+                                    off + offsetof(struct rr_pco_use, rpu_vltime),
+                                    sizeof(use->rpu_vltime), "Valid Lifetime: %u",
+                                    pntohl(&use->rpu_vltime));
+            if (pntohl(&use->rpu_pltime) == 0xffffffff)
+                proto_tree_add_text(opt_tree, tvb,
+                                    off + offsetof(struct rr_pco_use, rpu_pltime),
+                                    sizeof(use->rpu_pltime), "Preferred Lifetime: infinity");
+            else
+                proto_tree_add_text(opt_tree, tvb,
+                                    off + offsetof(struct rr_pco_use, rpu_pltime),
+                                    sizeof(use->rpu_pltime), "Preferred Lifetime: %u",
+                                    pntohl(&use->rpu_pltime));
+            tf = proto_tree_add_text(opt_tree, tvb,
+                                     flagoff = off + offsetof(struct rr_pco_use, rpu_flags),
+                                     sizeof(use->rpu_flags), "Flags: 0x%08x",
+                                     pntohl(&use->rpu_flags));
+            field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
+            flags = tvb_get_guint8(tvb, flagoff);
+            proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
+                                decode_boolean_bitfield(flags,
+                                                        ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, 32,
+                                                        "Decrement valid lifetime", "No decrement valid lifetime"));
+            proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
+                                decode_boolean_bitfield(flags,
+                                                        ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, 32,
+                                                        "Decrement preferred lifetime",
+                                                        "No decrement preferred lifetime"));
+            proto_tree_add_text(opt_tree, tvb,
+                                off + offsetof(struct rr_pco_use, rpu_prefix),
+                                sizeof(use->rpu_prefix), "UsePrefix: %s",
+                                ip6_to_str(&use->rpu_prefix));
+        }
 
     }
 }
@@ -1352,75 +1414,77 @@ dissect_rrenum(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
  * See I-D draft-vida-mld-v2-08
  */
 static const value_string mldrv2ModesNames[] = {
-  { 1, "Include" },
-  { 2, "Exclude" },
-  { 3, "Changed to include" },
-  { 4, "Changed to exclude" },
-  { 5, "Allow new sources" },
-  { 6, "Block old sources" },
-  { 0, NULL }
+    { 1, "Include" },
+    { 2, "Exclude" },
+    { 3, "Changed to include" },
+    { 4, "Changed to exclude" },
+    { 5, "Allow new sources" },
+    { 6, "Block old sources" },
+    { 0, NULL }
 };
 
 static void
 dissect_mldrv2( tvbuff_t *tvb, guint32 offset, guint16 count, proto_tree *tree )
 {
-  proto_tree *sub_tree;
-  proto_item *tf;
-
-  guint8 recordType, auxDataLen;
-  guint32 sourceNb, recordSize, localOffset;
-  struct e_in6_addr addr;
-
-  for( ; count; count--, offset += recordSize ) {
-    localOffset = offset;
-    recordType = tvb_get_guint8( tvb, localOffset );
-    localOffset += 1;
-    auxDataLen = tvb_get_guint8( tvb, localOffset );
-    localOffset += 1;
-    sourceNb = tvb_get_ntohs( tvb, localOffset );
-    localOffset += 2;
-    recordSize = 4 + 16 + (16 * sourceNb) + (auxDataLen * 4);
-
-    tvb_get_ipv6(tvb, localOffset, &addr);
-    tf = proto_tree_add_text( tree, tvb, offset, recordSize,
+    proto_tree *sub_tree;
+    proto_item *tf;
+
+    guint8 recordType, auxDataLen;
+    guint32 sourceNb, recordSize, localOffset;
+    struct e_in6_addr addr;
+
+    for( ; count; count--, offset += recordSize ) {
+        localOffset = offset;
+        recordType = tvb_get_guint8( tvb, localOffset );
+        localOffset += 1;
+        auxDataLen = tvb_get_guint8( tvb, localOffset );
+        localOffset += 1;
+        sourceNb = tvb_get_ntohs( tvb, localOffset );
+        localOffset += 2;
+        recordSize = 4 + 16 + (16 * sourceNb) + (auxDataLen * 4);
+
+        tvb_get_ipv6(tvb, localOffset, &addr);
+        tf = proto_tree_add_text( tree, tvb, offset, recordSize,
 #ifdef INET6
-                             "%s: %s (%s)", val_to_str(recordType, mldrv2ModesNames,"Unknown mode"),
-                             get_hostname6(&addr), ip6_to_str(&addr)
+                                  "%s: %s (%s)", val_to_str(recordType, mldrv2ModesNames,"Unknown mode"),
+                                  get_hostname6(&addr), ip6_to_str(&addr)
 #else
-                             "%s: %s", val_to_str(recordType, mldrv2ModesNames,"Unknown mode"),
-                             ip6_to_str(&addr)
+                                  "%s: %s", val_to_str(recordType, mldrv2ModesNames,"Unknown mode"),
+                                  ip6_to_str(&addr)
 #endif
-                             );
-    sub_tree = proto_item_add_subtree(tf, ett_multicastRR);
-
-    proto_tree_add_text( sub_tree, tvb, offset,   1, "Mode: %s",
-                        val_to_str(recordType, mldrv2ModesNames,"Unknown mode") );
-    proto_tree_add_text( sub_tree, tvb, offset+1, 1, "Aux data len: %u", auxDataLen * 4);
-    proto_tree_add_text( sub_tree, tvb, localOffset, 16, "Multicast Address: %s", ip6_to_str(&addr) );
-    localOffset += 16;
-
-    for( ; sourceNb; sourceNb--, localOffset += 16 ) {
-      tvb_get_ipv6(tvb, localOffset, &addr);
-      proto_tree_add_text( sub_tree, tvb, localOffset, 16,
+            );
+        sub_tree = proto_item_add_subtree(tf, ett_multicastRR);
+
+        proto_tree_add_text( sub_tree, tvb, offset,   1, "Mode: %s (%u)",
+                             val_to_str(recordType, mldrv2ModesNames,"Unknown mode"), recordType );
+        proto_tree_add_text( sub_tree, tvb, offset+1, 1, "Aux data len: %u", auxDataLen * 4);
+        proto_tree_add_text( sub_tree, tvb, offset+2, 2, "Number of Sources: %u", sourceNb);
+        proto_tree_add_text( sub_tree, tvb, localOffset, 16, "Multicast Address: %s", ip6_to_str(&addr) );
+        localOffset += 16;
+
+        for( ; sourceNb; sourceNb--, localOffset += 16 ) {
+            tvb_get_ipv6(tvb, localOffset, &addr);
+            proto_tree_add_text( sub_tree, tvb, localOffset, 16,
 #ifdef INET6
-                          "Source Address: %s (%s)", get_hostname6(&addr), ip6_to_str(&addr) );
+                                 "Source Address: %s (%s)", get_hostname6(&addr), ip6_to_str(&addr)
 #else
-                          "Source Address: %s", ip6_to_str(&addr) );
+                                 "Source Address: %s", ip6_to_str(&addr)
 #endif
+                );
+        }
     }
-  }
 }
 
 static void
 dissect_mldqv2(tvbuff_t *tvb, guint32 offset, guint16 count, proto_tree *tree)
 {
-  struct e_in6_addr addr;
+    struct e_in6_addr addr;
 
-  for ( ; count; count--, offset += 16) {
-      tvb_get_ipv6(tvb, offset, &addr);
-      proto_tree_add_text(tree, tvb, offset, 16,
-                         "Source Address: %s (%s)", get_hostname6(&addr), ip6_to_str(&addr));
-  }
+    for ( ; count; count--, offset += 16) {
+        tvb_get_ipv6(tvb, offset, &addr);
+        proto_tree_add_text(tree, tvb, offset, 16,
+                            "Source Address: %s (%s)", get_hostname6(&addr), ip6_to_str(&addr));
+    }
 }
 
 static void
@@ -1429,7 +1493,6 @@ dissect_icmpv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
     proto_tree *icmp6_tree, *field_tree;
     proto_item *ti, *hidden_item, *tf = NULL;
     struct icmp6_hdr icmp6_hdr, *dp;
-    struct icmp6_nodeinfo *ni = NULL;
     const char *codename, *typename;
     const char *colcodename, *coltypename;
     int len;
@@ -1440,841 +1503,821 @@ dissect_icmpv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
     int offset;
     tvbuff_t *next_tvb;
 
-    if (check_col(pinfo->cinfo, COL_PROTOCOL))
-       col_set_str(pinfo->cinfo, COL_PROTOCOL, "ICMPv6");
-    if (check_col(pinfo->cinfo, COL_INFO))
-       col_clear(pinfo->cinfo, COL_INFO);
+    col_set_str(pinfo->cinfo, COL_PROTOCOL, "ICMPv6");
+    col_clear(pinfo->cinfo, COL_INFO);
 
     offset = 0;
     tvb_memcpy(tvb, (guint8 *)&icmp6_hdr, offset, sizeof icmp6_hdr);
     dp = &icmp6_hdr;
-    codename = typename = colcodename = coltypename = "Unknown";
+    typename = coltypename = val_to_str (dp->icmp6_type, icmpv6_type_str, "Unknown");
+    codename = colcodename = NULL;
+
     len = sizeof(*dp);
     switch (dp->icmp6_type) {
     case ICMP6_DST_UNREACH:
-       typename = coltypename = "Unreachable";
-       switch (dp->icmp6_code) {
-       case ICMP6_DST_UNREACH_NOROUTE:
-           codename = colcodename = "Route unreachable";
-           break;
-       case ICMP6_DST_UNREACH_ADMIN:
-           codename = colcodename = "Administratively prohibited";
-           break;
-       case ICMP6_DST_UNREACH_NOTNEIGHBOR:
-           codename = colcodename = "Not a neighbor";
-           break;
-       case ICMP6_DST_UNREACH_ADDR:
-           codename = colcodename = "Address unreachable";
-           break;
-       case ICMP6_DST_UNREACH_NOPORT:
-           codename = colcodename = "Port unreachable";
-           break;
-       }
-       break;
-    case ICMP6_PACKET_TOO_BIG:
-       typename = coltypename = "Too big";
-       codename = colcodename = NULL;
-       break;
+        codename = colcodename = val_to_str (dp->icmp6_code, icmpv6_unreach_code_str, "Unknown");
+        break;
     case ICMP6_TIME_EXCEEDED:
-       typename = coltypename = "Time exceeded";
-       switch (dp->icmp6_code) {
-       case ICMP6_TIME_EXCEED_TRANSIT:
-           codename = colcodename = "In-transit";
-           break;
-       case ICMP6_TIME_EXCEED_REASSEMBLY:
-           codename = colcodename = "Reassembly";
-           break;
-       }
+        codename = colcodename = val_to_str (dp->icmp6_code, icmpv6_timeex_code_str, "Unknown");
         break;
     case ICMP6_PARAM_PROB:
-       typename = coltypename = "Parameter problem";
-       switch (dp->icmp6_code) {
-       case ICMP6_PARAMPROB_HEADER:
-           codename = colcodename = "Header";
-           break;
-       case ICMP6_PARAMPROB_NEXTHEADER:
-           codename = colcodename = "Next header";
-           break;
-       case ICMP6_PARAMPROB_OPTION:
-           codename = colcodename = "Option";
-           break;
-       }
+        codename = colcodename = val_to_str (dp->icmp6_code, icmpv6_paramprob_code_str, "Unknown");
         break;
-    case ICMP6_ECHO_REQUEST:
-       typename = coltypename = "Echo request";
-       codename = colcodename = NULL;
-       break;
-    case ICMP6_ECHO_REPLY:
-       typename = coltypename = "Echo reply";
-       codename = colcodename = NULL;
-       break;
-    case ICMP6_MEMBERSHIP_QUERY:
-       typename = coltypename = "Multicast listener query";
-       codename = colcodename = NULL;
-       break;
-    case ICMP6_MEMBERSHIP_REPORT:
-       typename = coltypename = "Multicast listener report";
-       codename = colcodename = NULL;
-       break;
-    case ICMP6_MEMBERSHIP_REDUCTION:
-       typename = coltypename = "Multicast listener done";
-       codename = colcodename = NULL;
-       break;
     case ND_ROUTER_SOLICIT:
-       typename = coltypename = "Router solicitation";
-       codename = colcodename = NULL;
-       len = sizeof(struct nd_router_solicit);
-       break;
+        len = sizeof(struct nd_router_solicit);
+        break;
     case ND_ROUTER_ADVERT:
-       typename = coltypename = "Router advertisement";
-       codename = colcodename = NULL;
-       len = sizeof(struct nd_router_advert);
-       break;
+        len = sizeof(struct nd_router_advert);
+        break;
     case ND_NEIGHBOR_SOLICIT:
-       typename = coltypename = "Neighbor solicitation";
-       codename = colcodename = NULL;
-       len = sizeof(struct nd_neighbor_solicit);
-       break;
+        len = sizeof(struct nd_neighbor_solicit);
+        break;
     case ND_NEIGHBOR_ADVERT:
-       typename = coltypename = "Neighbor advertisement";
-       codename = colcodename = NULL;
-       len = sizeof(struct nd_neighbor_advert);
-       break;
+        len = sizeof(struct nd_neighbor_advert);
+        break;
     case ND_REDIRECT:
-       typename = coltypename = "Redirect";
-       codename = colcodename = NULL;
-       len = sizeof(struct nd_redirect);
-       break;
+        len = sizeof(struct nd_redirect);
+        break;
     case ICMP6_ROUTER_RENUMBERING:
-       typename = coltypename = "Router renumbering";
-       switch (dp->icmp6_code) {
-       case ICMP6_ROUTER_RENUMBERING_COMMAND:
-           codename = colcodename = "Command";
-           break;
-       case ICMP6_ROUTER_RENUMBERING_RESULT:
-           codename = colcodename = "Result";
-           break;
-       case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
-           codename = colcodename = "Sequence number reset";
-           break;
-       }
-       len = sizeof(struct icmp6_router_renum);
-       break;
+        codename = colcodename = val_to_str (dp->icmp6_code, icmpv6_router_renum_code_str, "Unknown");
+        len = sizeof(struct icmp6_router_renum);
+        break;
     case ICMP6_NI_QUERY:
     case ICMP6_NI_REPLY:
-       ni = (struct icmp6_nodeinfo *)dp;
-       if (ni->ni_type == ICMP6_NI_QUERY) {
-           typename = coltypename = "Node information query";
-           switch (ni->ni_code) {
-           case ICMP6_NI_SUBJ_IPV6:
-               codename = "Query subject = IPv6 addresses";
-               break;
-           case ICMP6_NI_SUBJ_FQDN:
-               if (tvb_bytes_exist(tvb, offset, sizeof(*ni)))
-                   codename = "Query subject = DNS name";
-               else
-                   codename = "Query subject = empty";
-               break;
-           case ICMP6_NI_SUBJ_IPV4:
-               codename = "Query subject = IPv4 addresses";
-               break;
-           }
-       } else {
-           typename = coltypename = "Node information reply";
-           switch (ni->ni_code) {
-           case ICMP6_NI_SUCCESS:
-               codename = "Successful";
-               break;
-           case ICMP6_NI_REFUSED:
-               codename = "Refused";
-               break;
-           case ICMP6_NI_UNKNOWN:
-               codename = "Unknown query type";
-               break;
-           }
-       }
-       colcodename = val_to_str(pntohs(&ni->ni_qtype), names_nodeinfo_qtype,
-           "Unknown");
-       len = sizeof(struct icmp6_nodeinfo);
-       break;
+    {
+        struct icmp6_nodeinfo icmp6_nodeinfo, *ni;
+
+        ni = &icmp6_nodeinfo;
+        tvb_memcpy(tvb, (guint8 *)ni, offset, sizeof *ni);
+
+        if (ni->ni_type == ICMP6_NI_QUERY) {
+            switch (ni->ni_code) {
+            case ICMP6_NI_SUBJ_IPV6:
+                codename = "Query subject = IPv6 addresses";
+                break;
+            case ICMP6_NI_SUBJ_FQDN:
+                if (tvb_bytes_exist(tvb, offset, sizeof(*ni)))
+                    codename = "Query subject = DNS name";
+                else
+                    codename = "Query subject = empty";
+                break;
+            case ICMP6_NI_SUBJ_IPV4:
+                codename = "Query subject = IPv4 addresses";
+                break;
+            default:
+                codename = "Unknown";
+                break;
+            }
+        } else {
+            switch (ni->ni_code) {
+            case ICMP6_NI_SUCCESS:
+                codename = "Successful";
+                break;
+            case ICMP6_NI_REFUSED:
+                codename = "Refused";
+                break;
+            case ICMP6_NI_UNKNOWN:
+                codename = "Unknown query type";
+                break;
+            default:
+                codename = "Unknown";
+                break;
+            }
+        }
+        colcodename = val_to_str(pntohs(&ni->ni_qtype), names_nodeinfo_qtype, "Unknown");
+        len = sizeof(struct icmp6_nodeinfo);
+        break;
+    }
     case ICMP6_MIP6_DHAAD_REQUEST:
-       typename = coltypename = "Dynamic Home Agent Address Discovery Request";
-       codename = "Should always be zero";
-       colcodename = NULL;
-       break;
     case ICMP6_MIP6_DHAAD_REPLY:
-       typename = coltypename = "Dynamic Home Agent Address Discovery Reply";
-       codename = "Should always be zero";
-       colcodename = NULL;
-       break;
     case ICMP6_MIP6_MPS:
-       typename = coltypename = "Mobile Prefix Solicitation";
-       codename = "Should always be zero";
-       colcodename = NULL;
-       break;
     case ICMP6_MIP6_MPA:
-       typename = coltypename = "Mobile Prefix Advertisement";
-       codename = "Should always be zero";
-       colcodename = NULL;
-       break;
-       case ICMP6_CERT_PATH_SOL:
-               typename = coltypename = "Certification Path Solicitation";
-       codename = "Should always be zero";
-       colcodename = NULL;
-       break;
-       case ICMP6_CERT_PATH_AD:
-               typename = coltypename = "Certification Path Advertisement";
-       codename = "Should always be zero";
-       colcodename = NULL;
-       break;
+    case ICMP6_CERT_PATH_SOL:
+    case ICMP6_CERT_PATH_AD:
     case ICMP6_MLDV2_REPORT:
-       typename = coltypename = "Multicast Listener Report Message v2";
-       codename = "Should always be zero";
-       colcodename = NULL;
-       break;
-               case ICMP6_EXPERIMENTAL_MOBILITY:
-                       typename = coltypename ="Experimental Mobility";
-                       switch (dp->icmp6_data8[0]) {
-                               case FMIP6_SUBTYPE_RTSOLPR:
-                                       typename = coltypename ="RtSolPr (ICMPv6 Experimental Mobility)";
-                                       codename = "Should always be zero";
-                                       colcodename = NULL;
-                                       break;
-                               case FMIP6_SUBTYPE_PRRTADV:
-                                       typename = coltypename ="PrRtAdv (ICMPv6 Experimental Mobility)";
-                                       codename = val_to_str(dp->icmp6_code, names_fmip6_prrtadv_code, "Unknown");
-                                       colcodename = NULL;
-                                       break;
-                               case FMIP6_SUBTYPE_HI:
-                                       typename = coltypename ="HI (ICMPv6 Experimental Mobility)";
-                                       codename = val_to_str(dp->icmp6_code, names_fmip6_hi_code, "Unknown");
-                                       colcodename = NULL;
-                                       break;
-                               case FMIP6_SUBTYPE_HACK:
-                                       typename = coltypename ="HAck (ICMPv6 Experimental Mobility)";
-                                       codename = val_to_str(dp->icmp6_code, names_fmip6_hack_code, "Unknown");
-                                       colcodename = NULL;
-                                       break;
-                       }
-                       break;
-    }
+        codename = "Should always be zero";
+        break;
+    case ICMP6_EXPERIMENTAL_MOBILITY:
+        switch (dp->icmp6_data8[0]) {
+        case FMIP6_SUBTYPE_RTSOLPR:
+            typename = coltypename = "RtSolPr (ICMPv6 Experimental Mobility)";
+            codename = "Should always be zero";
+            break;
+        case FMIP6_SUBTYPE_PRRTADV:
+            typename = coltypename = "PrRtAdv (ICMPv6 Experimental Mobility)";
+            codename = val_to_str(dp->icmp6_code, names_fmip6_prrtadv_code, "Unknown");
+            break;
+        case FMIP6_SUBTYPE_HI:
+            typename = coltypename = "HI (ICMPv6 Experimental Mobility)";
+            codename = val_to_str(dp->icmp6_code, names_fmip6_hi_code, "Unknown");
+            break;
+        case FMIP6_SUBTYPE_HACK:
+            typename = coltypename = "HAck (ICMPv6 Experimental Mobility)";
+            codename = val_to_str(dp->icmp6_code, names_fmip6_hack_code, "Unknown");
+            break;
+        default:
+            codename = colcodename = "Unknown";
+            break;
+        } /* switch (dp->icmp6_data8[0]) */
+        break;
+    default:
+        codename = colcodename = "Unknown";
+        break;
+    } /* switch (dp->icmp6_type) */
 
     if (check_col(pinfo->cinfo, COL_INFO)) {
-       char typebuf[256], codebuf[256];
-
-       if (coltypename && strcmp(coltypename, "Unknown") == 0) {
-           g_snprintf(typebuf, sizeof(typebuf), "Unknown (0x%02x)",
-               dp->icmp6_type);
-           coltypename = typebuf;
-       }
-       if (colcodename && strcmp(colcodename, "Unknown") == 0) {
-           g_snprintf(codebuf, sizeof(codebuf), "Unknown (0x%02x)",
-               dp->icmp6_code);
-           colcodename = codebuf;
-       }
-       if (colcodename) {
-           col_add_fstr(pinfo->cinfo, COL_INFO, "%s (%s)", coltypename, colcodename);
-       } else {
-           col_add_str(pinfo->cinfo, COL_INFO, coltypename);
-       }
+        char typebuf[256], codebuf[256];
+        
+        
+        if (pinfo->destport == 0x0dd8 && dp->icmp6_type == ICMP6_ECHO_REQUEST) {
+            /* RFC 4380 
+             * 5.2.9. Direct IPv6 Connectivity Test 
+             */
+            col_set_str(pinfo->cinfo, COL_PROTOCOL, "Teredo");    
+            col_set_str(pinfo->cinfo, COL_INFO, "Direct IPv6 Connectivity Test");
+        } else {   
+            if (coltypename && strcmp(coltypename, "Unknown") == 0) {
+                g_snprintf(typebuf, sizeof(typebuf), "Unknown (0x%02x)",
+                           dp->icmp6_type);
+                coltypename = typebuf;
+            }
+            if (colcodename && strcmp(colcodename, "Unknown") == 0) {
+                g_snprintf(codebuf, sizeof(codebuf), "Unknown (0x%02x)",
+                           dp->icmp6_code);
+                colcodename = codebuf;
+            }
+            if (colcodename) {
+                col_add_fstr(pinfo->cinfo, COL_INFO, "%s (%s)", coltypename, colcodename);
+            } else {
+                col_add_str(pinfo->cinfo, COL_INFO, coltypename);
+            }
+        }
     }
 
     if (tree) {
-       /* !!! specify length */
-       ti = proto_tree_add_item(tree, proto_icmpv6, tvb, offset, -1, FALSE);
-       icmp6_tree = proto_item_add_subtree(ti, ett_icmpv6);
-
-       proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_type, tvb,
-           offset + offsetof(struct icmp6_hdr, icmp6_type), 1,
-           dp->icmp6_type,
-           "Type: %u (%s)", dp->icmp6_type, typename);
-       if (codename) {
-           proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_code, tvb,
-               offset + offsetof(struct icmp6_hdr, icmp6_code), 1,
-               dp->icmp6_code,
-               "Code: %u (%s)", dp->icmp6_code, codename);
-       } else {
-           proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_code, tvb,
-               offset + offsetof(struct icmp6_hdr, icmp6_code), 1,
-               dp->icmp6_code,
-               "Code: %u", dp->icmp6_code);
-       }
-       cksum = (guint16)g_htons(dp->icmp6_cksum);
-       length = tvb_length(tvb);
-       reported_length = tvb_reported_length(tvb);
-       if (!pinfo->fragmented && length >= reported_length) {
-           /* The packet isn't part of a fragmented datagram and isn't
-              truncated, so we can checksum it. */
-
-           /* Set up the fields of the pseudo-header. */
-           cksum_vec[0].ptr = pinfo->src.data;
-           cksum_vec[0].len = pinfo->src.len;
-           cksum_vec[1].ptr = pinfo->dst.data;
-           cksum_vec[1].len = pinfo->dst.len;
-           cksum_vec[2].ptr = (const guint8 *)&phdr;
-           phdr[0] = g_htonl(tvb_reported_length(tvb));
-           phdr[1] = g_htonl(IP_PROTO_ICMPV6);
-           cksum_vec[2].len = 8;
-           cksum_vec[3].len = tvb_reported_length(tvb);
-           cksum_vec[3].ptr = tvb_get_ptr(tvb, offset, cksum_vec[3].len);
-           computed_cksum = in_cksum(cksum_vec, 4);
-           if (computed_cksum == 0) {
-               proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_checksum,
-                       tvb,
-                       offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
-                       cksum,
-                       "Checksum: 0x%04x [correct]", cksum);
-           } else {
-               hidden_item = proto_tree_add_boolean(icmp6_tree, hf_icmpv6_checksum_bad,
-                       tvb,
-                       offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
-                       TRUE);
-               PROTO_ITEM_SET_HIDDEN(hidden_item);
-               proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_checksum,
-                       tvb,
-                       offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
-                       cksum,
-                       "Checksum: 0x%04x [incorrect, should be 0x%04x]",
-                       cksum, in_cksum_shouldbe(cksum, computed_cksum));
-           }
-       } else {
-           proto_tree_add_uint(icmp6_tree, hf_icmpv6_checksum, tvb,
-               offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
-               cksum);
-       }
-
-       /* decode... */
-       switch (dp->icmp6_type) {
-       case ICMP6_DST_UNREACH:
-       case ICMP6_TIME_EXCEEDED:
-           dissect_contained_icmpv6(tvb, offset + sizeof(*dp), pinfo,
-               icmp6_tree);
-           break;
-       case ICMP6_PACKET_TOO_BIG:
-           proto_tree_add_text(icmp6_tree, tvb,
-               offset + offsetof(struct icmp6_hdr, icmp6_mtu), 4,
-               "MTU: %u", pntohl(&dp->icmp6_mtu));
-           dissect_contained_icmpv6(tvb, offset + sizeof(*dp), pinfo,
-               icmp6_tree);
-           break;
-       case ICMP6_PARAM_PROB:
-           proto_tree_add_text(icmp6_tree, tvb,
-               offset + offsetof(struct icmp6_hdr, icmp6_pptr), 4,
-               "Problem pointer: 0x%04x", pntohl(&dp->icmp6_pptr));
-           dissect_contained_icmpv6(tvb, offset + sizeof(*dp), pinfo,
-               icmp6_tree);
-           break;
-       case ICMP6_ECHO_REQUEST:
-       case ICMP6_ECHO_REPLY:
-           proto_tree_add_text(icmp6_tree, tvb,
-               offset + offsetof(struct icmp6_hdr, icmp6_id), 2,
-               "ID: 0x%04x", (guint16)g_ntohs(dp->icmp6_id));
-           proto_tree_add_text(icmp6_tree, tvb,
-               offset + offsetof(struct icmp6_hdr, icmp6_seq), 2,
-               "Sequence: 0x%04x", (guint16)g_ntohs(dp->icmp6_seq));
-           next_tvb = tvb_new_subset(tvb, offset + sizeof(*dp), -1, -1);
-           call_dissector(data_handle,next_tvb, pinfo, icmp6_tree);
-           break;
-       case ICMP6_MEMBERSHIP_QUERY:
-       case ICMP6_MEMBERSHIP_REPORT:
-       case ICMP6_MEMBERSHIP_REDUCTION:
+        /* !!! specify length */
+        ti = proto_tree_add_item(tree, proto_icmpv6, tvb, offset, -1, FALSE);
+        icmp6_tree = proto_item_add_subtree(ti, ett_icmpv6);
+
+        proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_type, tvb,
+                                   offset + offsetof(struct icmp6_hdr, icmp6_type), 1,
+                                   dp->icmp6_type,
+                                   "Type: %u (%s)", dp->icmp6_type, typename);
+        if (codename) {
+            proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_code, tvb,
+                                       offset + offsetof(struct icmp6_hdr, icmp6_code), 1,
+                                       dp->icmp6_code,
+                                       "Code: %u (%s)", dp->icmp6_code, codename);
+        } else {
+            proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_code, tvb,
+                                       offset + offsetof(struct icmp6_hdr, icmp6_code), 1,
+                                       dp->icmp6_code,
+                                       "Code: %u", dp->icmp6_code);
+        }
+        cksum = (guint16)g_htons(dp->icmp6_cksum);
+        length = tvb_length(tvb);
+        reported_length = tvb_reported_length(tvb);
+        if (!pinfo->fragmented && length >= reported_length) {
+            /* The packet isn't part of a fragmented datagram and isn't
+               truncated, so we can checksum it. */
+
+            /* Set up the fields of the pseudo-header. */
+            cksum_vec[0].ptr = pinfo->src.data;
+            cksum_vec[0].len = pinfo->src.len;
+            cksum_vec[1].ptr = pinfo->dst.data;
+            cksum_vec[1].len = pinfo->dst.len;
+            cksum_vec[2].ptr = (const guint8 *)&phdr;
+            phdr[0] = g_htonl(tvb_reported_length(tvb));
+            phdr[1] = g_htonl(IP_PROTO_ICMPV6);
+            cksum_vec[2].len = 8;
+            cksum_vec[3].len = tvb_reported_length(tvb);
+            cksum_vec[3].ptr = tvb_get_ptr(tvb, offset, cksum_vec[3].len);
+            computed_cksum = in_cksum(cksum_vec, 4);
+            if (computed_cksum == 0) {
+                proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_checksum,
+                                           tvb,
+                                           offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
+                                           cksum,
+                                           "Checksum: 0x%04x [correct]", cksum);
+            } else {
+                hidden_item = proto_tree_add_boolean(icmp6_tree, hf_icmpv6_checksum_bad,
+                                                     tvb,
+                                                     offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
+                                                     TRUE);
+                PROTO_ITEM_SET_HIDDEN(hidden_item);
+                proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_checksum,
+                                           tvb,
+                                           offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
+                                           cksum,
+                                           "Checksum: 0x%04x [incorrect, should be 0x%04x]",
+                                           cksum, in_cksum_shouldbe(cksum, computed_cksum));
+            }
+        } else {
+            proto_tree_add_uint(icmp6_tree, hf_icmpv6_checksum, tvb,
+                                offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
+                                cksum);
+        }
+
+#define ICMP6_DATA_OFFSET 4
+#define ICMP6_SEQ_OFFSET 6
+        /* decode... */
+        switch (dp->icmp6_type) {
+        case ICMP6_DST_UNREACH:
+        case ICMP6_TIME_EXCEEDED:
+            dissect_contained_icmpv6(tvb, offset + sizeof(*dp), pinfo,
+                                     icmp6_tree);
+            break;
+        case ICMP6_PACKET_TOO_BIG:
+            proto_tree_add_text(icmp6_tree, tvb,
+                                offset + ICMP6_DATA_OFFSET, 4,
+                                "MTU: %u", pntohl(&dp->icmp6_mtu));
+            dissect_contained_icmpv6(tvb, offset + sizeof(*dp), pinfo,
+                                     icmp6_tree);
+            break;
+        case ICMP6_PARAM_PROB:
+            proto_tree_add_text(icmp6_tree, tvb,
+                                offset + ICMP6_DATA_OFFSET, 4,
+                                "Problem pointer: 0x%04x", pntohl(&dp->icmp6_pptr));
+            dissect_contained_icmpv6(tvb, offset + sizeof(*dp), pinfo,
+                                     icmp6_tree);
+            break;
+        case ICMP6_ECHO_REQUEST:
+        case ICMP6_ECHO_REPLY:
+            proto_tree_add_text(icmp6_tree, tvb,
+                                offset + ICMP6_DATA_OFFSET, 2,
+                                "ID: 0x%04x", (guint16)g_ntohs(dp->icmp6_id));
+            proto_tree_add_text(icmp6_tree, tvb,
+                                offset + ICMP6_SEQ_OFFSET, 2,
+                                "Sequence: 0x%04x", (guint16)g_ntohs(dp->icmp6_seq));
+
+            if (pinfo->destport == 0x0dd8 && dp->icmp6_type == ICMP6_ECHO_REQUEST) {
+                /* RFC 4380 
+                 * 5.2.9. Direct IPv6 Connectivity Test 
+                 */
+                proto_tree_add_text(icmp6_tree, tvb, offset + ICMP6_SEQ_OFFSET + 2, 4,
+                                    "Nonce: 0x%08x", tvb_get_ntohl(tvb, offset + ICMP6_SEQ_OFFSET + 2));
+            } else {
+                next_tvb = tvb_new_subset(tvb, offset + sizeof(*dp), -1, -1);
+                call_dissector(data_handle,next_tvb, pinfo, icmp6_tree);
+            }
+            break;
+        case ICMP6_MEMBERSHIP_QUERY:
+        case ICMP6_MEMBERSHIP_REPORT:
+        case ICMP6_MEMBERSHIP_REDUCTION:
 #define MLDV2_MINLEN 28
 #define MLDV1_MINLEN 24
-           if (dp->icmp6_type == ICMP6_MEMBERSHIP_QUERY) {
-               if (length >= MLDV2_MINLEN) {
-                   guint32 mrc;
-                   guint16 qqi;
-                   guint8 flag;
-                   guint16 nsrcs;
-
-                   mrc = g_ntohs(dp->icmp6_maxdelay);
-                   flag = tvb_get_guint8(tvb, offset + sizeof(*dp) + 16);
-                   qqi = tvb_get_guint8(tvb, offset + sizeof(*dp) + 16 + 1);
-                   nsrcs = tvb_get_ntohs(tvb, offset + sizeof(*dp) + 16 + 2);
-
-                   if (mrc >= 32768)
-                       mrc = ((mrc & 0x0fff) | 0x1000) <<
-                               (((mrc & 0x7000) >> 12) + 3);
-                   proto_tree_add_text(icmp6_tree, tvb,
-                       offset + offsetof(struct icmp6_hdr, icmp6_maxdelay), 2,
-                       "Maximum response delay[ms]: %u", mrc);
-
-                   proto_tree_add_text(icmp6_tree, tvb, offset + sizeof(*dp),
-                       16, "Multicast Address: %s",
-                       ip6_to_str((const struct e_in6_addr *)(tvb_get_ptr(tvb,
-                           offset + sizeof *dp, sizeof (struct e_in6_addr)))));
-
-                   proto_tree_add_text(icmp6_tree, tvb,
-                       offset + sizeof(*dp) + 16, 1, "S Flag: %s",
-                       flag & 0x08 ? "ON" : "OFF");
-                   proto_tree_add_text(icmp6_tree, tvb,
-                       offset + sizeof(*dp) + 16, 1, "Robustness: %d",
-                       flag & 0x07);
-                   if (qqi >= 128)
-                       qqi = ((qqi & 0x0f) | 0x10) << (((qqi & 0x70) >> 4) + 3);
-                   proto_tree_add_text(icmp6_tree, tvb,
-                       offset + sizeof(*dp) + 17, 1, "QQI: %d", qqi);
-
-                   dissect_mldqv2(tvb, offset + sizeof(*dp) + 20, nsrcs,
-                       icmp6_tree);
-                   break;
-               } else if (length > MLDV1_MINLEN) {
-                   next_tvb = tvb_new_subset(tvb, offset + sizeof(*dp), -1, -1);
-                   call_dissector(data_handle,next_tvb, pinfo, tree);
-                   break;
-               }
-               /* MLDv1 Query -> FALLTHOUGH */
-           }
+            if (dp->icmp6_type == ICMP6_MEMBERSHIP_QUERY) {
+                if (length >= MLDV2_MINLEN) {
+                    guint32 mrc;
+                    guint16 qqi;
+                    guint8 flag;
+                    guint16 nsrcs;
+
+                    mrc = g_ntohs(dp->icmp6_maxdelay);
+                    flag = tvb_get_guint8(tvb, offset + sizeof(*dp) + 16);
+                    qqi = tvb_get_guint8(tvb, offset + sizeof(*dp) + 16 + 1);
+                    nsrcs = tvb_get_ntohs(tvb, offset + sizeof(*dp) + 16 + 2);
+
+                    if (mrc >= 32768)
+                        mrc = ((mrc & 0x0fff) | 0x1000) <<
+                            (((mrc & 0x7000) >> 12) + 3);
+                    proto_tree_add_text(icmp6_tree, tvb,
+                                        offset + ICMP6_DATA_OFFSET, 2,
+                                        "Maximum response delay[ms]: %u", mrc);
+
+                    proto_tree_add_text(icmp6_tree, tvb, offset + sizeof(*dp),
+                                        16, "Multicast Address: %s",
+                                        ip6_to_str((const struct e_in6_addr *)(tvb_get_ptr(tvb,
+                                                                                           offset + sizeof *dp, sizeof (struct e_in6_addr)))));
+
+                    proto_tree_add_text(icmp6_tree, tvb,
+                                        offset + sizeof(*dp) + 16, 1, "S Flag: %s",
+                                        flag & 0x08 ? "ON" : "OFF");
+                    proto_tree_add_text(icmp6_tree, tvb,
+                                        offset + sizeof(*dp) + 16, 1, "Robustness: %d",
+                                        flag & 0x07);
+                    if (qqi >= 128)
+                        qqi = ((qqi & 0x0f) | 0x10) << (((qqi & 0x70) >> 4) + 3);
+                    proto_tree_add_text(icmp6_tree, tvb,
+                                        offset + sizeof(*dp) + 17, 1, "QQI: %d", qqi);
+
+                    dissect_mldqv2(tvb, offset + sizeof(*dp) + 20, nsrcs,
+                                   icmp6_tree);
+                    break;
+                } else if (length > MLDV1_MINLEN) {
+                    next_tvb = tvb_new_subset(tvb, offset + sizeof(*dp), -1, -1);
+                    call_dissector(data_handle,next_tvb, pinfo, tree);
+                    break;
+                }
+                /* MLDv1 Query -> FALLTHOUGH */
+            } /* if (dp->icmp6_type == ICMP6_MEMBERSHIP_QUERY) */
 #undef MLDV2_MINLEN
 #undef MLDV1_MINLEN
-           proto_tree_add_text(icmp6_tree, tvb,
-               offset + offsetof(struct icmp6_hdr, icmp6_maxdelay), 2,
-               "Maximum response delay: %u",
-               (guint16)g_ntohs(dp->icmp6_maxdelay));
-           proto_tree_add_text(icmp6_tree, tvb, offset + sizeof(*dp), 16,
-               "Multicast Address: %s",
-               ip6_to_str((const struct e_in6_addr *)(tvb_get_ptr(tvb, offset + sizeof *dp, sizeof (struct e_in6_addr)))));
-           break;
-       case ND_ROUTER_SOLICIT:
-           dissect_icmpv6ndopt(tvb, offset + sizeof(*dp), pinfo, icmp6_tree);
-           break;
-       case ICMP6_MLDV2_REPORT: {
-         guint16 nbRecords;
-
-         nbRecords = tvb_get_ntohs( tvb, offset+4+2 );
-         dissect_mldrv2( tvb, offset+4+2+2, nbRecords, icmp6_tree );
-         break;
-       }
-       case ND_ROUTER_ADVERT:
-         {
-           struct nd_router_advert nd_router_advert, *ra;
-           int flagoff;
-           guint32 ra_flags;
-
-           ra = &nd_router_advert;
-           tvb_memcpy(tvb, (guint8 *)ra, offset, sizeof *ra);
-
-           /* Current hop limit */
-           proto_tree_add_uint(icmp6_tree, hf_icmpv6_ra_cur_hop_limit, tvb,
-               offset + offsetof(struct nd_router_advert, nd_ra_curhoplimit),
-               1, ra->nd_ra_curhoplimit);
-
-           /* Flags */
-           flagoff = offset + offsetof(struct nd_router_advert, nd_ra_flags_reserved);
-           ra_flags = tvb_get_guint8(tvb, flagoff);
-           tf = proto_tree_add_text(icmp6_tree, tvb, flagoff, 1, "Flags: 0x%02x", ra_flags);
-           field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
-
-           proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
-               decode_boolean_bitfield(ra_flags,
-                       ND_RA_FLAG_MANAGED, 8, "Managed", "Not managed"));
-           proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
-               decode_boolean_bitfield(ra_flags,
-                       ND_RA_FLAG_OTHER, 8, "Other", "Not other"));
-           proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
-               decode_boolean_bitfield(ra_flags,
-                       ND_RA_FLAG_HOME_AGENT, 8,
-                       "Home Agent", "Not Home Agent"));
-           proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
-               decode_enumerated_bitfield(ra_flags, ND_RA_FLAG_RTPREF_MASK, 8,
-               names_router_pref, "Router preference: %s"));
-
-           /* Router lifetime */
-           proto_tree_add_uint(icmp6_tree, hf_icmpv6_ra_router_lifetime, tvb,
-               offset + offsetof(struct nd_router_advert, nd_ra_router_lifetime),
-               2, (guint16)g_ntohs(ra->nd_ra_router_lifetime));
-
-           /* Reachable time */
-           proto_tree_add_uint(icmp6_tree, hf_icmpv6_ra_reachable_time, tvb,
-               offset + offsetof(struct nd_router_advert, nd_ra_reachable), 4,
-               pntohl(&ra->nd_ra_reachable));
-
-           /* Retrans timer */
-           proto_tree_add_uint(icmp6_tree, hf_icmpv6_ra_retrans_timer, tvb,
-               offset + offsetof(struct nd_router_advert, nd_ra_retransmit), 4,
-               pntohl(&ra->nd_ra_retransmit));
-
-           dissect_icmpv6ndopt(tvb, offset + sizeof(struct nd_router_advert), pinfo, icmp6_tree);
-           break;
-         }
-       case ND_NEIGHBOR_SOLICIT:
-         {
-           struct nd_neighbor_solicit nd_neighbor_solicit, *ns;
-
-           ns = &nd_neighbor_solicit;
-           tvb_memcpy(tvb, (guint8 *)ns, offset, sizeof *ns);
-           proto_tree_add_text(icmp6_tree, tvb,
-                       offset + offsetof(struct nd_neighbor_solicit, nd_ns_target), 16,
+            proto_tree_add_text(icmp6_tree, tvb,
+                                offset + ICMP6_DATA_OFFSET, 2,
+                                "Maximum response delay: %u",
+                                (guint16)g_ntohs(dp->icmp6_maxdelay));
+            proto_tree_add_text(icmp6_tree, tvb, offset + sizeof(*dp), 16,
+                                "Multicast Address: %s",
+                                ip6_to_str((const struct e_in6_addr *)(tvb_get_ptr(tvb, offset + sizeof *dp, sizeof (struct e_in6_addr)))));
+            break;
+        case ND_ROUTER_SOLICIT:
+            dissect_icmpv6ndopt(tvb, offset + sizeof(*dp), pinfo, icmp6_tree);
+            break;
+        case ICMP6_MLDV2_REPORT:
+        {
+            guint16 nbRecords;
+
+            nbRecords = tvb_get_ntohs( tvb, offset+4+2 );
+            proto_tree_add_text( icmp6_tree, tvb, offset+4+2, 2, "Number of records: %u", nbRecords );
+            dissect_mldrv2( tvb, offset+4+2+2, nbRecords, icmp6_tree );
+            break;
+        }
+#define ND_RA_CURHOPLIMIT_OFFSET 4
+#define ND_RA_FLAGS_RESERVED_OFFSET 5
+#define ND_RA_ROUTER_LIFETIME_OFFSET 6
+        case ND_ROUTER_ADVERT:
+        {
+            struct nd_router_advert nd_router_advert, *ra;
+            int flagoff;
+            guint32 ra_flags;
+
+            ra = &nd_router_advert;
+            tvb_memcpy(tvb, (guint8 *)ra, offset, sizeof *ra);
+
+            /* Current hop limit */
+            proto_tree_add_uint(icmp6_tree, hf_icmpv6_ra_cur_hop_limit, tvb,
+                                offset + ND_RA_CURHOPLIMIT_OFFSET,
+                                1, ra->nd_ra_curhoplimit);
+
+            /* Flags */
+            flagoff = offset + ND_RA_FLAGS_RESERVED_OFFSET;
+            ra_flags = tvb_get_guint8(tvb, flagoff);
+            tf = proto_tree_add_text(icmp6_tree, tvb, flagoff, 1, "Flags: 0x%02x", ra_flags);
+            field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
+
+            proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
+                                decode_boolean_bitfield(ra_flags,
+                                                        ND_RA_FLAG_MANAGED, 8, "Managed", "Not managed"));
+            proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
+                                decode_boolean_bitfield(ra_flags,
+                                                        ND_RA_FLAG_OTHER, 8, "Other", "Not other"));
+            proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
+                                decode_boolean_bitfield(ra_flags,
+                                                        ND_RA_FLAG_HOME_AGENT, 8,
+                                                        "Home Agent", "Not Home Agent"));
+            proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
+                                decode_enumerated_bitfield(ra_flags, ND_RA_FLAG_RTPREF_MASK, 8,
+                                                           names_router_pref, "Router preference: %s"));
+            proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
+                                decode_boolean_bitfield(ra_flags,
+                                                        ND_RA_FLAG_ND_PROXY, 8,
+                                                        "Proxied", "Not Proxied"));
+
+            /* Router lifetime */
+            proto_tree_add_uint(icmp6_tree, hf_icmpv6_ra_router_lifetime, tvb,
+                                offset + ND_RA_ROUTER_LIFETIME_OFFSET,
+                                2, (guint16)g_ntohs(ra->nd_ra_router_lifetime));
+
+            /* Reachable time */
+            proto_tree_add_uint(icmp6_tree, hf_icmpv6_ra_reachable_time, tvb,
+                                offset + offsetof(struct nd_router_advert, nd_ra_reachable), 4,
+                                pntohl(&ra->nd_ra_reachable));
+
+            /* Retrans timer */
+            proto_tree_add_uint(icmp6_tree, hf_icmpv6_ra_retrans_timer, tvb,
+                                offset + offsetof(struct nd_router_advert, nd_ra_retransmit), 4,
+                                pntohl(&ra->nd_ra_retransmit));
+
+            dissect_icmpv6ndopt(tvb, offset + sizeof(struct nd_router_advert), pinfo, icmp6_tree);
+            break;
+        }
+        case ND_NEIGHBOR_SOLICIT:
+        {
+            struct nd_neighbor_solicit nd_neighbor_solicit, *ns;
+
+            ns = &nd_neighbor_solicit;
+            tvb_memcpy(tvb, (guint8 *)ns, offset, sizeof *ns);
+            proto_tree_add_text(icmp6_tree, tvb,
+                                offset + offsetof(struct nd_neighbor_solicit, nd_ns_target), 16,
 #ifdef INET6
-                       "Target: %s (%s)",
-                       get_hostname6(&ns->nd_ns_target),
+                                "Target: %s (%s)",
+                                get_hostname6(&ns->nd_ns_target),
 #else
-                       "Target: %s",
+                                "Target: %s",
 #endif
-                       ip6_to_str(&ns->nd_ns_target));
-
-           dissect_icmpv6ndopt(tvb, offset + sizeof(*ns), pinfo, icmp6_tree);
-           break;
-         }
-       case ND_NEIGHBOR_ADVERT:
-         {
-           int flagoff, targetoff;
-           guint32 na_flags;
-           struct e_in6_addr na_target;
-
-           flagoff = offset + offsetof(struct nd_neighbor_advert, nd_na_flags_reserved);
-           na_flags = tvb_get_ntohl(tvb, flagoff);
-
-           tf = proto_tree_add_text(icmp6_tree, tvb, flagoff, 4, "Flags: 0x%08x", na_flags);
-           field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
-           proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
-               decode_boolean_bitfield(na_flags,
-                       ND_NA_FLAG_ROUTER, 32, "Router", "Not router"));
-           proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
-               decode_boolean_bitfield(na_flags,
-                       ND_NA_FLAG_SOLICITED, 32, "Solicited", "Not adverted"));
-           proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
-               decode_boolean_bitfield(na_flags,
-                       ND_NA_FLAG_OVERRIDE, 32, "Override", "Not override"));
-
-           targetoff = offset + offsetof(struct nd_neighbor_advert, nd_na_target);
-           tvb_memcpy(tvb, (guint8 *)&na_target, targetoff, sizeof na_target);
-           proto_tree_add_text(icmp6_tree, tvb, targetoff, 16,
+                                ip6_to_str(&ns->nd_ns_target));
+
+            dissect_icmpv6ndopt(tvb, offset + sizeof(*ns), pinfo, icmp6_tree);
+            break;
+        }
+#define ND_NA_FLAGS_RESERVED_OFFSET 4
+        case ND_NEIGHBOR_ADVERT:
+        {
+            int flagoff, targetoff;
+            guint32 na_flags;
+            struct e_in6_addr na_target;
+
+            flagoff = offset + ND_NA_FLAGS_RESERVED_OFFSET;
+            na_flags = tvb_get_ntohl(tvb, flagoff);
+
+            tf = proto_tree_add_text(icmp6_tree, tvb, flagoff, 4, "Flags: 0x%08x", na_flags);
+            field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
+            proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
+                                decode_boolean_bitfield(na_flags,
+                                                        ND_NA_FLAG_ROUTER, 32, "Router", "Not router"));
+            proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
+                                decode_boolean_bitfield(na_flags,
+                                                        ND_NA_FLAG_SOLICITED, 32, "Solicited", "Not adverted"));
+            proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
+                                decode_boolean_bitfield(na_flags,
+                                                        ND_NA_FLAG_OVERRIDE, 32, "Override", "Not override"));
+
+            targetoff = offset + offsetof(struct nd_neighbor_advert, nd_na_target);
+            tvb_memcpy(tvb, (guint8 *)&na_target, targetoff, sizeof na_target);
+            proto_tree_add_text(icmp6_tree, tvb, targetoff, 16,
 #ifdef INET6
-                       "Target: %s (%s)",
-                       get_hostname6(&na_target),
+                                "Target: %s (%s)",
+                                get_hostname6(&na_target),
 #else
-                       "Target: %s",
+                                "Target: %s",
 #endif
-                       ip6_to_str(&na_target));
-
-           dissect_icmpv6ndopt(tvb, offset + sizeof(struct nd_neighbor_advert), pinfo, icmp6_tree);
-           break;
-         }
-       case ND_REDIRECT:
-         {
-           struct nd_redirect nd_redirect, *rd;
-
-           rd = &nd_redirect;
-           tvb_memcpy(tvb, (guint8 *)rd, offset, sizeof *rd);
-           proto_tree_add_text(icmp6_tree, tvb,
-                       offset + offsetof(struct nd_redirect, nd_rd_target), 16,
+                                ip6_to_str(&na_target));
+
+            dissect_icmpv6ndopt(tvb, offset + sizeof(struct nd_neighbor_advert), pinfo, icmp6_tree);
+            break;
+        }
+        case ND_REDIRECT:
+        {
+            struct nd_redirect nd_redirect, *rd;
+
+            rd = &nd_redirect;
+            tvb_memcpy(tvb, (guint8 *)rd, offset, sizeof *rd);
+            proto_tree_add_text(icmp6_tree, tvb,
+                                offset + offsetof(struct nd_redirect, nd_rd_target), 16,
 #ifdef INET6
-                       "Target: %s (%s)",
-                       get_hostname6(&rd->nd_rd_target),
+                                "Target: %s (%s)",
+                                get_hostname6(&rd->nd_rd_target),
 #else
-                       "Target: %s",
+                                "Target: %s",
 #endif
-                       ip6_to_str(&rd->nd_rd_target));
+                                ip6_to_str(&rd->nd_rd_target));
 
-           proto_tree_add_text(icmp6_tree, tvb,
-                       offset + offsetof(struct nd_redirect, nd_rd_dst), 16,
+            proto_tree_add_text(icmp6_tree, tvb,
+                                offset + offsetof(struct nd_redirect, nd_rd_dst), 16,
 #ifdef INET6
-                       "Destination: %s (%s)",
-                       get_hostname6(&rd->nd_rd_dst),
+                                "Destination: %s (%s)",
+                                get_hostname6(&rd->nd_rd_dst),
 #else
-                       "Destination: %s",
+                                "Destination: %s",
 #endif
-                       ip6_to_str(&rd->nd_rd_dst));
-
-           dissect_icmpv6ndopt(tvb, offset + sizeof(*rd), pinfo, icmp6_tree);
-           break;
-         }
-       case ICMP6_ROUTER_RENUMBERING:
-           dissect_rrenum(tvb, offset, pinfo, icmp6_tree);
-           break;
-       case ICMP6_NI_QUERY:
-       case ICMP6_NI_REPLY:
-           ni = (struct icmp6_nodeinfo *)dp;
-           proto_tree_add_text(icmp6_tree, tvb,
-               offset + offsetof(struct icmp6_nodeinfo, ni_qtype),
-               sizeof(ni->ni_qtype),
-               "Query type: 0x%04x (%s)", pntohs(&ni->ni_qtype),
-               val_to_str(pntohs(&ni->ni_qtype), names_nodeinfo_qtype,
-               "Unknown"));
-           dissect_nodeinfo(tvb, offset, pinfo, icmp6_tree);
-           break;
-       case ICMP6_MIP6_DHAAD_REQUEST:
-           proto_tree_add_text(icmp6_tree, tvb,
-               offset + 4, 2, "Identifier: %d (0x%02x)",
-               tvb_get_ntohs(tvb, offset + 4),
-               tvb_get_ntohs(tvb, offset + 4));
-           proto_tree_add_text(icmp6_tree, tvb,
-               offset + 6, 2, "Reserved: %d",
-               tvb_get_ntohs(tvb, offset + 6));
-           break;
-       case ICMP6_MIP6_DHAAD_REPLY:
-           proto_tree_add_text(icmp6_tree, tvb,
-               offset + 4, 2, "Identifier: %d (0x%02x)",
-               tvb_get_ntohs(tvb, offset + 4),
-               tvb_get_ntohs(tvb, offset + 4));
-           proto_tree_add_text(icmp6_tree, tvb,
-               offset + 6, 2, "Reserved: %d",
-               tvb_get_ntohs(tvb, offset + 6));
-           /* Show all Home Agent Addresses */
-           {
-               int i, suboffset;
-               int ha_num = (length - 8)/16;
-
-               for (i = 0; i < ha_num; i++) {
-                   suboffset = 16 * i;
-                   proto_tree_add_ipv6(icmp6_tree, hf_icmpv6_haad_ha_addrs,
-                       tvb, offset + 8 + suboffset, 16,
-                       tvb_get_ptr(tvb, offset + 8 + suboffset, 16));
-               }
-           }
-           break;
-       case ICMP6_MIP6_MPS:
-           proto_tree_add_text(icmp6_tree, tvb,
-               offset + 4, 2, "Identifier: %d (0x%02x)",
-               tvb_get_ntohs(tvb, offset + 4),
-               tvb_get_ntohs(tvb, offset + 4));
-           proto_tree_add_text(icmp6_tree, tvb,
-               offset + 6, 2, "Reserved: %d",
-               tvb_get_ntohs(tvb, offset + 6));
-           break;
-       case ICMP6_MIP6_MPA:
-           proto_tree_add_text(icmp6_tree, tvb,
-               offset + 4, 2, "Identifier: %d (0x%02x)",
-               tvb_get_ntohs(tvb, offset + 4),
-               tvb_get_ntohs(tvb, offset + 4));
-           proto_tree_add_text(icmp6_tree, tvb,
-               offset + 6, 1,
-               decode_boolean_bitfield(tvb_get_guint8(tvb, offset + 6),
-                   0x80, 8,
-                   "Managed Address Configuration",
-                   "No Managed Address Configuration"));
-           proto_tree_add_text(icmp6_tree, tvb,
-               offset + 6, 1,
-               decode_boolean_bitfield(tvb_get_guint8(tvb, offset + 6),
-                   0x40, 8,
-                   "Other Stateful Configuration",
-                   "No Other Stateful Configuration"));
-           proto_tree_add_text(icmp6_tree, tvb,
-               offset + 7, 1, "Reserved: %d",
-               tvb_get_guint8(tvb, offset + 7));
-           /* Show all options */
-           dissect_icmpv6ndopt(tvb, offset + 8, pinfo, icmp6_tree);
-           break;
-       case ICMP6_EXPERIMENTAL_MOBILITY:
-               switch (dp->icmp6_data8[0]) {
-                       case FMIP6_SUBTYPE_RTSOLPR:
-                               {
-                                       struct fmip6_rtsolpr *rtsolpr;
-                                       rtsolpr = (struct fmip6_rtsolpr*) dp;
-                                       proto_tree_add_text(icmp6_tree, tvb,
-                                                       offset + 4, 1,
-                                                       "Subtype: Router Solicitation for Proxy Advertisement");
-                                       proto_tree_add_text(icmp6_tree, tvb,
-                                                       offset + 6, 2,
-                                                       "Identifier: %d", pntohs(&rtsolpr->fmip6_rtsolpr_id));
-                                       dissect_icmpv6fmip6opt(tvb, offset + sizeof(*dp), icmp6_tree);
-                                       break;
-                               }
-                       case FMIP6_SUBTYPE_PRRTADV:
-                               {
-                                       struct fmip6_prrtadv *prrtadv;
-                                       prrtadv = (struct fmip6_prrtadv*) dp;
-                                       proto_tree_add_text(icmp6_tree, tvb,
-                                                       offset + 4, 1,
-                                                       "Subtype: Proxy Router Advertisement");
-                                       proto_tree_add_text(icmp6_tree, tvb,
-                                                       offset + 6, 2,
-                                                       "Identifier: %d", pntohs(&prrtadv->fmip6_prrtadv_id));
-                                       dissect_icmpv6fmip6opt(tvb, offset + sizeof(*dp), icmp6_tree);
-                                       break;
-                               }
-                       case FMIP6_SUBTYPE_HI:
-                               {
-                                       struct fmip6_hi *hi;
-                                       int flagoff;
-                                       guint8 hi_flags;
-                                       hi = (struct fmip6_hi*) dp;
-                                       proto_tree_add_text(icmp6_tree, tvb,
-                                                       offset + 4, 1,
-                                                       "Subtype: Handover Initiate");
-
-                                       flagoff = offset + offsetof(struct fmip6_hi, fmip6_hi_flags_reserved);
-                                       hi_flags = tvb_get_guint8(tvb, flagoff);
-                                       tf = proto_tree_add_text(icmp6_tree, tvb, flagoff, 1, "Flags: 0x%02x", hi_flags);
-                                       field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
-                                       proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
-                                                       decode_boolean_bitfield(hi_flags,
-                                                               FMIP_HI_FLAG_ASSIGNED, 8, "Assigned", "Not assigned"));
-                                       proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
-                                                       decode_boolean_bitfield(hi_flags,
-                                                               FMIP_HI_FLAG_BUFFER, 8, "Buffered", "Not buffered"));
-                                       proto_tree_add_text(icmp6_tree, tvb,
-                                                       offset + 6, 2,
-                                                       "Identifier: %d", pntohs(&hi->fmip6_hi_id));
-                                       dissect_icmpv6fmip6opt(tvb, offset + sizeof(*dp), icmp6_tree);
-                                       break;
-                               }
-                       case FMIP6_SUBTYPE_HACK:
-                               {
-                                       struct fmip6_hack *hack;
-                                       hack = (struct fmip6_hack*) dp;
-                                       proto_tree_add_text(icmp6_tree, tvb,
-                                                       offset + 4, 1,
-                                                       "Subtype: Handover Acknowledge");
-                                       proto_tree_add_text(icmp6_tree, tvb,
-                                                       offset + 6, 2,
-                                                       "Identifier: %d", pntohs(&hack->fmip6_hack_id));
-                                       dissect_icmpv6fmip6opt(tvb, offset + sizeof(*dp), icmp6_tree);
-                                       break;
-                               }
-               }
-           break;
-       case ICMP6_CERT_PATH_AD:
-               /*RFC 3971 6.4.2.  Certification Path Advertisement Message Format */
-               offset = offset +4;
-               proto_tree_add_text(icmp6_tree, tvb, offset, -1,"Certification Path Advertisement Message");
-
-               /* Identifier A 16-bit unsigned integer field */
-               proto_tree_add_item(icmp6_tree, hf_icmpv6_identifier, tvb, offset, 2, FALSE);
-               offset = offset + 2;
-               /* All Components  A 16-bit unsigned integer field*/
-               proto_tree_add_item(icmp6_tree, hf_icmpv6_all_comp, tvb, offset, 2, FALSE);
-               offset = offset + 2;
-
-               /* Component A 16-bit unsigned integer field, used to inform the receiver
-                * which certificate is being sent.
-                */
-               proto_tree_add_item(icmp6_tree, hf_icmpv6_comp, tvb, offset, 2, FALSE);
-               offset = offset + 2;
-
-               /* Reserved */
-               proto_tree_add_text(icmp6_tree, tvb, offset, 2,"Reserved");
-               offset = offset + 2;
-
-               dissect_icmpv6ndopt(tvb, offset, pinfo, icmp6_tree);
-               break;
-       default:
-           next_tvb = tvb_new_subset(tvb, offset + sizeof(*dp), -1, -1);
-           call_dissector(data_handle,next_tvb, pinfo, tree);
-           break;
-       }
-    }
+                                ip6_to_str(&rd->nd_rd_dst));
+
+            dissect_icmpv6ndopt(tvb, offset + sizeof(*rd), pinfo, icmp6_tree);
+            break;
+        }
+        case ICMP6_ROUTER_RENUMBERING:
+            dissect_rrenum(tvb, offset, pinfo, icmp6_tree);
+            break;
+#define NI_QTYPE_OFFSET 4
+        case ICMP6_NI_QUERY:
+        case ICMP6_NI_REPLY:
+        {
+            struct icmp6_nodeinfo *ni = (struct icmp6_nodeinfo *)dp;
+            proto_tree_add_text(icmp6_tree, tvb,
+                                offset + NI_QTYPE_OFFSET,
+                                sizeof(ni->ni_qtype),
+                                "Query type: 0x%04x (%s)", pntohs(&ni->ni_qtype),
+                                val_to_str(pntohs(&ni->ni_qtype), names_nodeinfo_qtype,
+                                           "Unknown"));
+            dissect_nodeinfo(tvb, offset, pinfo, icmp6_tree);
+            break;
+        }
+        case ICMP6_MIP6_DHAAD_REQUEST:
+            proto_tree_add_text(icmp6_tree, tvb,
+                                offset + 4, 2, "Identifier: %d (0x%02x)",
+                                tvb_get_ntohs(tvb, offset + 4),
+                                tvb_get_ntohs(tvb, offset + 4));
+            proto_tree_add_text(icmp6_tree, tvb,
+                                offset + 6, 2, "Reserved: %d",
+                                tvb_get_ntohs(tvb, offset + 6));
+            break;
+        case ICMP6_MIP6_DHAAD_REPLY:
+            proto_tree_add_text(icmp6_tree, tvb,
+                                offset + 4, 2, "Identifier: %d (0x%02x)",
+                                tvb_get_ntohs(tvb, offset + 4),
+                                tvb_get_ntohs(tvb, offset + 4));
+            proto_tree_add_text(icmp6_tree, tvb,
+                                offset + 6, 2, "Reserved: %d",
+                                tvb_get_ntohs(tvb, offset + 6));
+            /* Show all Home Agent Addresses */
+            {
+                int i, suboffset;
+                int ha_num = (length - 8)/16;
+
+                for (i = 0; i < ha_num; i++) {
+                    suboffset = 16 * i;
+                    proto_tree_add_ipv6(icmp6_tree, hf_icmpv6_haad_ha_addrs,
+                                        tvb, offset + 8 + suboffset, 16,
+                                        tvb_get_ptr(tvb, offset + 8 + suboffset, 16));
+                }
+            }
+            break;
+        case ICMP6_MIP6_MPS:
+            proto_tree_add_text(icmp6_tree, tvb,
+                                offset + 4, 2, "Identifier: %d (0x%02x)",
+                                tvb_get_ntohs(tvb, offset + 4),
+                                tvb_get_ntohs(tvb, offset + 4));
+            proto_tree_add_text(icmp6_tree, tvb,
+                                offset + 6, 2, "Reserved: %d",
+                                tvb_get_ntohs(tvb, offset + 6));
+            break;
+        case ICMP6_MIP6_MPA:
+            proto_tree_add_text(icmp6_tree, tvb,
+                                offset + 4, 2, "Identifier: %d (0x%02x)",
+                                tvb_get_ntohs(tvb, offset + 4),
+                                tvb_get_ntohs(tvb, offset + 4));
+            proto_tree_add_text(icmp6_tree, tvb,
+                                offset + 6, 1, "%s",
+                                decode_boolean_bitfield(tvb_get_guint8(tvb, offset + 6),
+                                                        0x80, 8,
+                                                        "Managed Address Configuration",
+                                                        "No Managed Address Configuration"));
+            proto_tree_add_text(icmp6_tree, tvb,
+                                offset + 6, 1, "%s",
+                                decode_boolean_bitfield(tvb_get_guint8(tvb, offset + 6),
+                                                        0x40, 8,
+                                                        "Other Stateful Configuration",
+                                                        "No Other Stateful Configuration"));
+            proto_tree_add_text(icmp6_tree, tvb,
+                                offset + 7, 1, "Reserved: %d",
+                                tvb_get_guint8(tvb, offset + 7));
+            /* Show all options */
+            dissect_icmpv6ndopt(tvb, offset + 8, pinfo, icmp6_tree);
+            break;
+        case ICMP6_EXPERIMENTAL_MOBILITY:
+            switch (dp->icmp6_data8[0]) {
+            case FMIP6_SUBTYPE_RTSOLPR:
+            {
+                struct fmip6_rtsolpr *rtsolpr;
+                rtsolpr = (struct fmip6_rtsolpr*) dp;
+                proto_tree_add_text(icmp6_tree, tvb,
+                                    offset + 4, 1,
+                                    "Subtype: Router Solicitation for Proxy Advertisement");
+                proto_tree_add_text(icmp6_tree, tvb,
+                                    offset + 6, 2,
+                                    "Identifier: %d", pntohs(&rtsolpr->fmip6_rtsolpr_id));
+                dissect_icmpv6fmip6opt(tvb, offset + sizeof(*dp), icmp6_tree);
+                break;
+            }
+            case FMIP6_SUBTYPE_PRRTADV:
+            {
+                struct fmip6_prrtadv *prrtadv;
+                prrtadv = (struct fmip6_prrtadv*) dp;
+                proto_tree_add_text(icmp6_tree, tvb,
+                                    offset + 4, 1,
+                                    "Subtype: Proxy Router Advertisement");
+                proto_tree_add_text(icmp6_tree, tvb,
+                                    offset + 6, 2,
+                                    "Identifier: %d", pntohs(&prrtadv->fmip6_prrtadv_id));
+                dissect_icmpv6fmip6opt(tvb, offset + sizeof(*dp), icmp6_tree);
+                break;
+            }
+            case FMIP6_SUBTYPE_HI:
+            {
+                struct fmip6_hi *hi;
+                int flagoff;
+                guint8 hi_flags;
+                hi = (struct fmip6_hi*) dp;
+                proto_tree_add_text(icmp6_tree, tvb,
+                                    offset + 4, 1,
+                                    "Subtype: Handover Initiate");
+
+                flagoff = offset + 5;
+                hi_flags = tvb_get_guint8(tvb, flagoff);
+                tf = proto_tree_add_text(icmp6_tree, tvb, flagoff, 1, "Flags: 0x%02x", hi_flags);
+                field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
+                proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
+                                    decode_boolean_bitfield(hi_flags,
+                                                            FMIP_HI_FLAG_ASSIGNED, 8, "Assigned", "Not assigned"));
+                proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
+                                    decode_boolean_bitfield(hi_flags,
+                                                            FMIP_HI_FLAG_BUFFER, 8, "Buffered", "Not buffered"));
+                proto_tree_add_text(icmp6_tree, tvb,
+                                    offset + 6, 2,
+                                    "Identifier: %d", pntohs(&hi->fmip6_hi_id));
+                dissect_icmpv6fmip6opt(tvb, offset + sizeof(*dp), icmp6_tree);
+                break;
+            }
+            case FMIP6_SUBTYPE_HACK:
+            {
+                struct fmip6_hack *hack;
+                hack = (struct fmip6_hack*) dp;
+                proto_tree_add_text(icmp6_tree, tvb,
+                                    offset + 4, 1,
+                                    "Subtype: Handover Acknowledge");
+                proto_tree_add_text(icmp6_tree, tvb,
+                                    offset + 6, 2,
+                                    "Identifier: %d", pntohs(&hack->fmip6_hack_id));
+                dissect_icmpv6fmip6opt(tvb, offset + sizeof(*dp), icmp6_tree);
+                break;
+            }
+            } /* switch (dp->icmp6_data8[0]) */
+            break;
+        case ICMP6_CERT_PATH_SOL:
+            /*RFC 3971 6.4.1.  Certification Path Solicitation Message Format */
+            offset += 4;
+            proto_tree_add_text(icmp6_tree, tvb, offset, -1,
+                                "Certification Path Solicitation Message");
+            /* Identifier A 16-bit unsigned integer field */
+            proto_tree_add_item(icmp6_tree, hf_icmpv6_identifier, tvb, offset,
+                                2, FALSE);
+            offset += 2;
+            /* Component A 16-bit unsigned integer field,
+             * 65,535 if the sender seeks to retrieve all certificates.
+             * Otherwise, set to the identifier that the receiver wants.
+             */
+            proto_tree_add_item(icmp6_tree, hf_icmpv6_comp, tvb, offset, 2,
+                                FALSE);
+            offset += 2;
+            dissect_icmpv6ndopt(tvb, offset, pinfo, icmp6_tree);
+            break;
+        case ICMP6_CERT_PATH_AD:
+            /*RFC 3971 6.4.2.  Certification Path Advertisement Message Format */
+            offset = offset +4;
+            proto_tree_add_text(icmp6_tree, tvb, offset, -1,"Certification Path Advertisement Message");
+
+            /* Identifier A 16-bit unsigned integer field */
+            proto_tree_add_item(icmp6_tree, hf_icmpv6_identifier, tvb, offset, 2, FALSE);
+            offset = offset + 2;
+            /* All Components  A 16-bit unsigned integer field*/
+            proto_tree_add_item(icmp6_tree, hf_icmpv6_all_comp, tvb, offset, 2, FALSE);
+            offset = offset + 2;
+
+            /* Component A 16-bit unsigned integer field, used to inform the receiver
+             * which certificate is being sent.
+             */
+            proto_tree_add_item(icmp6_tree, hf_icmpv6_comp, tvb, offset, 2, FALSE);
+            offset = offset + 2;
+
+            /* Reserved */
+            proto_tree_add_text(icmp6_tree, tvb, offset, 2,"Reserved");
+            offset = offset + 2;
+
+            dissect_icmpv6ndopt(tvb, offset, pinfo, icmp6_tree);
+            break;
+        default:
+            next_tvb = tvb_new_subset(tvb, offset + sizeof(*dp), -1, -1);
+            call_dissector(data_handle,next_tvb, pinfo, tree);
+            break;
+        } /* switch (dp->icmp6_type) */
+    } /* if (tree) */
 }
 
 void
 proto_register_icmpv6(void)
 {
-  static hf_register_info hf[] = {
-    { &hf_icmpv6_type,
-      { "Type",           "icmpv6.type",       FT_UINT8,  BASE_DEC, NULL, 0x0,
-       "", HFILL }},
-    { &hf_icmpv6_code,
-      { "Code",           "icmpv6.code",       FT_UINT8,  BASE_DEC, NULL, 0x0,
-       "", HFILL }},
-    { &hf_icmpv6_checksum,
-      { "Checksum",       "icmpv6.checksum",   FT_UINT16, BASE_HEX, NULL, 0x0,
-       "", HFILL }},
-    { &hf_icmpv6_checksum_bad,
-      { "Bad Checksum",   "icmpv6.checksum_bad", FT_BOOLEAN, BASE_NONE,        NULL, 0x0,
-       "", HFILL }},
-    { &hf_icmpv6_haad_ha_addrs,
-      { "Home Agent Addresses", "icmpv6.haad.ha_addrs",
-       FT_IPv6, BASE_HEX, NULL, 0x0,
-       "", HFILL }},
-    { &hf_icmpv6_ra_cur_hop_limit,
-      { "Cur hop limit",           "icmpv6.ra.cur_hop_limit", FT_UINT8,  BASE_DEC, NULL, 0x0,
-       "Current hop limit", HFILL }},
-    { &hf_icmpv6_ra_router_lifetime,
-      { "Router lifetime",           "icmpv6.ra.router_lifetime", FT_UINT16,  BASE_DEC, NULL, 0x0,
-       "Router lifetime (s)", HFILL }},
-    { &hf_icmpv6_ra_reachable_time,
-      { "Reachable time",           "icmpv6.ra.reachable_time", FT_UINT32,  BASE_DEC, NULL, 0x0,
-       "Reachable time (ms)", HFILL }},
-    { &hf_icmpv6_ra_retrans_timer,
-      { "Retrans timer",           "icmpv6.ra.retrans_timer", FT_UINT32,  BASE_DEC, NULL, 0x0,
-       "Retrans timer (ms)", HFILL }},
-    { &hf_icmpv6_option,
-      { "ICMPv6 Option",           "icmpv6.option", FT_NONE,  BASE_NONE, NULL, 0x0,
-       "Option", HFILL }},
-    { &hf_icmpv6_option_type,
-      { "Type",           "icmpv6.option.type", FT_UINT8,  BASE_DEC, VALS(option_vals), 0x0,
-       "Options type", HFILL }},
-    { &hf_icmpv6_option_length,
-      { "Length",           "icmpv6.option.length", FT_UINT8,  BASE_DEC, NULL, 0x0,
-       "Options length (in bytes)", HFILL }},
-       { &hf_icmpv6_opt_cga_pad_len,
-      { "Pad Length",           "icmpv6.option.cga.pad_length", FT_UINT8,  BASE_DEC, NULL, 0x0,
-       "Pad Length (in bytes)", HFILL }},
-       { &hf_icmpv6_opt_cga,
-      { "CGA",           "icmpv6.option.cga", FT_BYTES,  BASE_NONE, NULL, 0x0,
-       "CGA", HFILL }},
-       { &hf_icmpv6_opt_rsa_key_hash,
-      { "Key Hash",           "icmpv6.option.rsa.key_hash", FT_BYTES,  BASE_HEX, NULL, 0x0,
-       "Key Hash", HFILL }},
-       { &hf_icmpv6_opt_name_type,
-      { "Name Type",           "icmpv6.option.name_type", FT_UINT8,  BASE_DEC, VALS(icmpv6_option_name_type_vals), 0x0,
-       "Name Type", HFILL }},
-       { &hf_icmpv6_opt_name_x501,
-      { "DER Encoded X.501 Name",           "icmpv6.option.name_x501", FT_BYTES,  BASE_HEX, NULL, 0x0,
-       "DER Encoded X.501 Name", HFILL }},
-       { &hf_icmpv6_opt_name_fqdn,
-      { "FQDN",           "icmpv6.option.name_type.fqdn", FT_STRING,  BASE_NONE, NULL, 0x0,
-       "FQDN", HFILL }},
-       { &hf_icmpv6_opt_cert_type,
-      { "Cert Type",           "icmpv6.option.name_type", FT_UINT8,  BASE_DEC, VALS(icmpv6_option_cert_type_vals), 0x0,
-       "Cert Type", HFILL }},
-       { &hf_icmpv6_identifier,
-      { "Identifier",           "icmpv6.identifier", FT_UINT16,  BASE_DEC, NULL, 0x0,
-       "Identifier", HFILL }},
-       { &hf_icmpv6_all_comp,
-      { "All Components",           "icmpv6.all_comp", FT_UINT16,  BASE_DEC, NULL, 0x0,
-       "All Components", HFILL }},
-       { &hf_icmpv6_comp,
-      { "Component",           "icmpv6.comp", FT_UINT16,  BASE_DEC, NULL, 0x0,
-       "Component", HFILL }},
-    { &hf_icmpv6_x509if_Name,
-      { "Name", "icmpv6.x509_Name", FT_UINT32, BASE_DEC, VALS(x509if_Name_vals), 0,
-        "Name", HFILL }},
-    { &hf_icmpv6_x509af_Certificate,
-      { "Certificate", "icmpv6_x509_Certificate", FT_NONE, BASE_NONE, NULL, 0,
-        "Certificate", HFILL }},
-    { &hf_icmpv6_recursive_dns_serv,
-      { "Recursive DNS Servers", "icmpv6.recursive_dns_serv",
-       FT_IPv6, BASE_HEX, NULL, 0x0,
-       "Recursive DNS Servers", HFILL }},
-
-  };
-
-  static gint *ett[] = {
-    &ett_icmpv6,
-    &ett_icmpv6opt,
-    &ett_icmpv6flag,
-    &ett_nodeinfo_flag,
-    &ett_nodeinfo_subject4,
-    &ett_nodeinfo_subject6,
-    &ett_nodeinfo_node4,
-    &ett_nodeinfo_node6,
-    &ett_nodeinfo_nodebitmap,
-    &ett_nodeinfo_nodedns,
-    &ett_multicastRR,
-       &ett_icmpv6opt_name,
-  };
-
-  proto_icmpv6 = proto_register_protocol("Internet Control Message Protocol v6",
-                                        "ICMPv6", "icmpv6");
-  proto_register_field_array(proto_icmpv6, hf, array_length(hf));
-  proto_register_subtree_array(ett, array_length(ett));
-
-  register_dissector("icmpv6", dissect_icmpv6, proto_icmpv6);
+    static hf_register_info hf[] = {
+        { &hf_icmpv6_type,
+          { "Type",           "icmpv6.type",    FT_UINT8,  BASE_DEC, NULL, 0x0,
+            NULL, HFILL }},
+        { &hf_icmpv6_code,
+          { "Code",           "icmpv6.code",    FT_UINT8,  BASE_DEC, NULL, 0x0,
+            NULL, HFILL }},
+        { &hf_icmpv6_checksum,
+          { "Checksum",       "icmpv6.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
+            NULL, HFILL }},
+        { &hf_icmpv6_checksum_bad,
+          { "Bad Checksum",   "icmpv6.checksum_bad", FT_BOOLEAN, BASE_NONE,  NULL, 0x0,
+            NULL, HFILL }},
+        { &hf_icmpv6_haad_ha_addrs,
+          { "Home Agent Addresses", "icmpv6.haad.ha_addrs", FT_IPv6, BASE_NONE, NULL, 0x0,
+            NULL, HFILL }},
+        { &hf_icmpv6_ra_cur_hop_limit,
+          { "Cur hop limit",           "icmpv6.ra.cur_hop_limit", FT_UINT8,  BASE_DEC, NULL, 0x0,
+            "Current hop limit", HFILL }},
+        { &hf_icmpv6_ra_router_lifetime,
+          { "Router lifetime",         "icmpv6.ra.router_lifetime", FT_UINT16,  BASE_DEC, NULL, 0x0,
+            "Router lifetime (s)", HFILL }},
+        { &hf_icmpv6_ra_reachable_time,
+          { "Reachable time",          "icmpv6.ra.reachable_time", FT_UINT32,  BASE_DEC, NULL, 0x0,
+            "Reachable time (ms)", HFILL }},
+        { &hf_icmpv6_ra_retrans_timer,
+          { "Retrans timer",           "icmpv6.ra.retrans_timer", FT_UINT32,  BASE_DEC, NULL, 0x0,
+            "Retrans timer (ms)", HFILL }},
+        { &hf_icmpv6_option,
+          { "ICMPv6 Option",           "icmpv6.option", FT_NONE,  BASE_NONE, NULL, 0x0,
+            "Option", HFILL }},
+        { &hf_icmpv6_option_type,
+          { "Type",           "icmpv6.option.type", FT_UINT8,  BASE_DEC, VALS(option_vals), 0x0,
+            "Options type", HFILL }},
+        { &hf_icmpv6_option_length,
+          { "Length",         "icmpv6.option.length", FT_UINT8,  BASE_DEC, NULL, 0x0,
+            "Options length (in bytes)", HFILL }},
+        { &hf_icmpv6_opt_cga_pad_len,
+          { "Pad Length",     "icmpv6.option.cga.pad_length", FT_UINT8,  BASE_DEC, NULL, 0x0,
+            "Pad Length (in bytes)", HFILL }},
+        { &hf_icmpv6_opt_cga,
+          { "CGA",            "icmpv6.option.cga", FT_BYTES,  BASE_NONE, NULL, 0x0,
+            NULL, HFILL }},
+        { &hf_icmpv6_opt_cga_modifier,
+          { "Modifier",       "icmpv6.option.cga.modifier", FT_BYTES, BASE_NONE, NULL, 0x0,
+            NULL, HFILL }},
+        { &hf_icmpv6_opt_cga_subnet_prefix,
+          { "Subnet Prefix",  "icmpv6.option.cga.subnet_prefix", FT_BYTES, BASE_NONE, NULL, 0x0,
+            NULL, HFILL }},
+        { &hf_icmpv6_opt_cga_count,
+          { "Count",          "icmpv6.option.cga.count", FT_BYTES, BASE_NONE, NULL, 0x0,
+            NULL, HFILL }},
+        { &hf_icmpv6_opt_cga_ext_type,
+          { "Ext Type",       "icmpv6.option.cga.ext_type", FT_BYTES, BASE_NONE, NULL, 0x0,
+            NULL, HFILL }},
+        { &hf_icmpv6_opt_cga_ext_length,
+          { "Ext Length",     "icmpv6.option.cga.ext_length", FT_BYTES, BASE_NONE, NULL, 0x0,
+            NULL, HFILL }},
+        { &hf_icmpv6_opt_rsa_key_hash,
+          { "Key Hash",       "icmpv6.option.rsa.key_hash", FT_BYTES,  BASE_NONE, NULL, 0x0,
+            NULL, HFILL }},
+        { &hf_icmpv6_opt_name_type,
+          { "Name Type",      "icmpv6.option.name_type", FT_UINT8,  BASE_DEC, VALS(icmpv6_option_name_type_vals), 0x0,
+            NULL, HFILL }},
+        { &hf_icmpv6_opt_name_x501,
+          { "DER Encoded X.501 Name", "icmpv6.option.name_x501", FT_BYTES,  BASE_NONE, NULL, 0x0,
+            NULL, HFILL }},
+        { &hf_icmpv6_opt_name_fqdn,
+          { "FQDN",           "icmpv6.option.name_type.fqdn", FT_STRING,  BASE_NONE, NULL, 0x0,
+            NULL, HFILL }},
+        { &hf_icmpv6_opt_cert_type,
+          { "Cert Type",       "icmpv6.option.name_type", FT_UINT8,  BASE_DEC, VALS(icmpv6_option_cert_type_vals), 0x0,
+            NULL, HFILL }},
+        { &hf_icmpv6_identifier,
+          { "Identifier",      "icmpv6.identifier", FT_UINT16,  BASE_DEC, NULL, 0x0,
+            NULL, HFILL }},
+        { &hf_icmpv6_all_comp,
+          { "All Components",  "icmpv6.all_comp", FT_UINT16,  BASE_DEC, NULL, 0x0,
+            NULL, HFILL }},
+        { &hf_icmpv6_comp,
+          { "Component",       "icmpv6.comp", FT_UINT16,  BASE_DEC, NULL, 0x0,
+            NULL, HFILL }},
+        { &hf_icmpv6_x509if_Name,
+          { "Name",            "icmpv6.x509_Name", FT_UINT32, BASE_DEC, VALS(x509if_Name_vals), 0x0,
+            NULL, HFILL }},
+        { &hf_icmpv6_x509af_Certificate,
+          { "Certificate",     "icmpv6.x509_Certificate", FT_NONE, BASE_NONE, NULL, 0x0,
+            NULL, HFILL }},
+        { &hf_icmpv6_recursive_dns_serv,
+          { "Recursive DNS Servers", "icmpv6.recursive_dns_serv", FT_IPv6, BASE_NONE, NULL, 0x0,
+            NULL, HFILL }}
+    };
+
+    static gint *ett[] = {
+        &ett_icmpv6,
+        &ett_icmpv6opt,
+        &ett_icmpv6flag,
+        &ett_nodeinfo_flag,
+        &ett_nodeinfo_subject4,
+        &ett_nodeinfo_subject6,
+        &ett_nodeinfo_node4,
+        &ett_nodeinfo_node6,
+        &ett_nodeinfo_nodebitmap,
+        &ett_nodeinfo_nodedns,
+        &ett_multicastRR,
+        &ett_icmpv6opt_name,
+        &ett_cga_param_name
+    };
+
+    proto_icmpv6 = proto_register_protocol("Internet Control Message Protocol v6",
+                                           "ICMPv6", "icmpv6");
+    proto_register_field_array(proto_icmpv6, hf, array_length(hf));
+    proto_register_subtree_array(ett, array_length(ett));
+
+    register_dissector("icmpv6", dissect_icmpv6, proto_icmpv6);
 }
 
 void
 proto_reg_handoff_icmpv6(void)
 {
-  dissector_handle_t icmpv6_handle;
+    dissector_handle_t icmpv6_handle;
 
-  icmpv6_handle = create_dissector_handle(dissect_icmpv6, proto_icmpv6);
-  dissector_add("ip.proto", IP_PROTO_ICMPV6, icmpv6_handle);
+    icmpv6_handle = create_dissector_handle(dissect_icmpv6, proto_icmpv6);
+    dissector_add("ip.proto", IP_PROTO_ICMPV6, icmpv6_handle);
 
-  /*
-   * Get a handle for the IPv6 dissector.
-   */
-  ipv6_handle = find_dissector("ipv6");
-  data_handle = find_dissector("data");
+    /*
+     * Get a handle for the IPv6 dissector.
+     */
+    ipv6_handle = find_dissector("ipv6");
+    data_handle = find_dissector("data");
 }
+
+/*
+ * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=4 tabstop=8 expandtab
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */