/* packet-icmpv6.c * Routines for ICMPv6 packet disassembly * * $Id$ * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * MobileIPv6 support added by Tomislav Borosa * Copyright 2006, Nicolas DICHTEL - 6WIND - * * HMIPv6 support added by Martti Kuparinen * * FMIPv6 support added by Martin Andre * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #ifdef HAVE_UNISTD_H #include #endif #include #include #include #include #include #include #include #include #include #include "packet-ber.h" #include "packet-ipv6.h" #include "packet-dns.h" #include "packet-x509af.h" #include "packet-x509if.h" #ifndef offsetof #define offsetof(type, member) ((size_t)(&((type *)0)->member)) #endif /* * See, under http://www.ietf.org/internet-drafts/ * * draft-ietf-mobileip-ipv6-15.txt * * and * * draft-ietf-ipngwg-icmp-name-lookups-08.txt * * and * * draft-ietf-mobileip-hmipv6-05.txt * * and * * rfc4068.txt */ static int proto_icmpv6 = -1; static int hf_icmpv6_type = -1; static int hf_icmpv6_code = -1; static int hf_icmpv6_checksum = -1; static int hf_icmpv6_checksum_bad = -1; static int hf_icmpv6_haad_ha_addrs = -1; static int hf_icmpv6_ra_cur_hop_limit = -1; static int hf_icmpv6_ra_router_lifetime = -1; static int hf_icmpv6_ra_reachable_time = -1; static int hf_icmpv6_ra_retrans_timer = -1; static int hf_icmpv6_option = -1; 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; static int hf_icmpv6_opt_name_fqdn = -1; static int hf_icmpv6_opt_cert_type = -1; static int hf_icmpv6_identifier = -1; static int hf_icmpv6_all_comp = -1; static int hf_icmpv6_comp = -1; 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; static gint ett_nodeinfo_flag = -1; static gint ett_nodeinfo_subject4 = -1; static gint ett_nodeinfo_subject6 = -1; static gint ett_nodeinfo_node4 = -1; static gint ett_nodeinfo_node6 = -1; 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 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 } }; static const value_string names_rrenum_matchcode[] = { { 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} }; 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 } }; 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 } }; 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 } }; 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 } }; 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 } }; 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 } }; /* 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" }, /*29-252 Unassigned */ { 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 } }; static const value_string icmpv6_option_cert_type_vals[] = { { 1, "X.509v3 Certificate" }, { 0, NULL } }; static void dissect_contained_icmpv6(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { gboolean save_in_error_pkt; tvbuff_t *next_tvb; /* Save the current value of the "we're inside an error packet" flag, and set that flag; subdissectors may treat packets that are the payload of error packets differently from "real" packets. */ save_in_error_pkt = pinfo->in_error_pkt; pinfo->in_error_pkt = TRUE; next_tvb = tvb_new_subset(tvb, offset, -1, -1); /* 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); } else 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; } static void dissect_icmpv6ndopt(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { 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; again: if ((int)tvb_reported_length(tvb) <= offset) return; /* No more options left */ opt = &nd_opt_hdr; tvb_memcpy(tvb, (guint8 *)opt, offset, sizeof *opt); len = opt->nd_opt_len << 3; /* !!! specify length */ ti = proto_tree_add_item(tree, hf_icmpv6_option, tvb, offset, len, FALSE); 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 */ } typename = val_to_str(opt->nd_opt_type, option_vals, "Unknown"); /* Add option name to option root label */ 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); /* 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); /* 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; } 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; } 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; 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; 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; 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 */ { 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, #ifdef INET6 "Address of MAP: %s (%s)", get_hostname6(&map->nd_opt_map_address), #else "Address of MAP: %s", #endif 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; } 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; } offset += (opt->nd_opt_len << 3); /* Set length of option tree */ proto_item_set_len(ti, opt->nd_opt_len << 3); goto 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; 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; } /* * draft-ietf-ipngwg-icmp-name-lookups-07.txt * Note that the packet format was changed several times in the past. */ static const char * bitrange0(guint32 v, int s, char *buf, int buflen) { 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; } static const char * bitrange(tvbuff_t *tvb, int offset, int l, int s) { static char buf[1024]; char *q, *eq; 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; } } return buf + 1; } static void dissect_nodeinfo(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { proto_tree *field_tree; proto_item *tf; struct icmp6_nodeinfo icmp6_nodeinfo, *ni; int off; unsigned int j; int i, n, l, p; guint16 flags; const char *dname; guint32 ipaddr; ni = &icmp6_nodeinfo; tvb_memcpy(tvb, (guint8 *)ni, offset, sizeof *ni); /* 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); 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; 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; 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 */ 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; } /* 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 for "the rest of data" */ off = sizeof(*ni); /* rest of data */ if (!tvb_bytes_exist(tvb, offset, sizeof(*ni))) 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; } } 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; } } nodata:; /* the rest of data */ call_dissector(data_handle,tvb_new_subset(tvb, offset + off, -1, -1), pinfo, tree); } static void dissect_rrenum(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { proto_tree *field_tree, *opt_tree; proto_item *tf; struct icmp6_router_renum icmp6_router_renum, *rr; struct rr_pco_match rr_pco_match, *match; struct rr_pco_use rr_pco_use, *use; int flagoff, off; unsigned int l; guint8 flags; 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)); proto_tree_add_text(tree, tvb, offset + offsetof(struct icmp6_router_renum, rr_segnum), 1, "Segment number: 0x%02x", rr->rr_segnum); flagoff = offset + offsetof(struct icmp6_router_renum, rr_flags); flags = tvb_get_guint8(tvb, flagoff); tf = proto_tree_add_text(tree, tvb, flagoff, 1, "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(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*/ 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)); } } } /* * 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 } }; 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, #ifdef INET6 "%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) #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, #ifdef INET6 "Source Address: %s (%s)", get_hostname6(&addr), ip6_to_str(&addr) ); #else "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; 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 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; guint length, reported_length; vec_t cksum_vec[4]; guint32 phdr[2]; guint16 cksum, computed_cksum; 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); offset = 0; tvb_memcpy(tvb, (guint8 *)&icmp6_hdr, offset, sizeof icmp6_hdr); dp = &icmp6_hdr; codename = typename = colcodename = coltypename = "Unknown"; 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; 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; } 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; } 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; case ND_ROUTER_ADVERT: typename = coltypename = "Router advertisement"; codename = colcodename = NULL; 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; case ND_NEIGHBOR_ADVERT: typename = coltypename = "Neighbor advertisement"; codename = colcodename = NULL; len = sizeof(struct nd_neighbor_advert); break; case ND_REDIRECT: typename = coltypename = "Redirect"; codename = colcodename = NULL; 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; 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; 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_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; } 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); } } 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: #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 */ } #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, #ifdef INET6 "Target: %s (%s)", get_hostname6(&ns->nd_ns_target), #else "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, #ifdef INET6 "Target: %s (%s)", get_hostname6(&na_target), #else "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, #ifdef INET6 "Target: %s (%s)", get_hostname6(&rd->nd_rd_target), #else "Target: %s", #endif ip6_to_str(&rd->nd_rd_target)); 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), #else "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, "%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 + 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_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; } } } 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_cga_modifier, { "Modifier", "icmpv6.option.cga.modifier", FT_BYTES, BASE_HEX, NULL, 0x0, "Modifier", HFILL }}, { &hf_icmpv6_opt_cga_subnet_prefix, { "Subnet Prefix", "icmpv6.option.cga.subnet_prefix", FT_BYTES, BASE_HEX, NULL, 0x0, "Subnet Prefix", HFILL }}, { &hf_icmpv6_opt_cga_count, { "Count", "icmpv6.option.cga.count", FT_BYTES, BASE_HEX, NULL, 0x0, "Count", HFILL }}, { &hf_icmpv6_opt_cga_ext_type, { "Ext Type", "icmpv6.option.cga.ext_type", FT_BYTES, BASE_HEX, NULL, 0x0, "Ext Type", HFILL }}, { &hf_icmpv6_opt_cga_ext_length, { "Ext Length", "icmpv6.option.cga.ext_length", FT_BYTES, BASE_HEX, NULL, 0x0, "Ext Length", 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), 0x0, "Name", HFILL }}, { &hf_icmpv6_x509af_Certificate, { "Certificate", "icmpv6.x509_Certificate", FT_NONE, BASE_NONE, NULL, 0x0, "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, &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; 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"); }