2 * Routines for ICMPv6 packet disassembly
4 * $Id: packet-icmpv6.c,v 1.65 2002/01/30 22:58:54 guy Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@ethereal.com>
8 * Copyright 1998 Gerald Combs
10 * MobileIPv6 support added by Tomislav Borosa <tomislav.borosa@siemens.hr>
12 * HMIPv6 support added by Martti Kuparinen <martti.kuparinen@iki.fi>
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
42 #ifdef HAVE_SYS_TYPES_H
43 # include <sys/types.h>
46 #ifdef HAVE_NETINET_IN_H
47 # include <netinet/in.h>
52 #ifdef NEED_SNPRINTF_H
53 # include "snprintf.h"
56 #include <epan/packet.h>
57 #include "packet-ipv6.h"
58 #include "packet-dns.h"
60 #include <epan/resolv.h>
64 #define offsetof(type, member) ((size_t)(&((type *)0)->member))
68 * See, under http://www.ietf.org/internet-drafts/
70 * draft-ietf-mobileip-ipv6-15.txt
74 * draft-ietf-ipngwg-icmp-name-lookups-08.txt
78 * draft-ietf-mobileip-hmipv6-05.txt
81 static int proto_icmpv6 = -1;
82 static int hf_icmpv6_type = -1;
83 static int hf_icmpv6_code = -1;
84 static int hf_icmpv6_checksum = -1;
85 static int hf_icmpv6_checksum_bad = -1;
87 static gint ett_icmpv6 = -1;
88 static gint ett_icmpv6opt = -1;
89 static gint ett_icmpv6flag = -1;
90 static gint ett_nodeinfo_flag = -1;
91 static gint ett_nodeinfo_subject4 = -1;
92 static gint ett_nodeinfo_subject6 = -1;
93 static gint ett_nodeinfo_node4 = -1;
94 static gint ett_nodeinfo_node6 = -1;
95 static gint ett_nodeinfo_nodebitmap = -1;
96 static gint ett_nodeinfo_nodedns = -1;
98 static dissector_handle_t ipv6_handle;
99 static dissector_handle_t data_handle;
101 static const value_string names_nodeinfo_qtype[] = {
102 { NI_QTYPE_NOOP, "NOOP" },
103 { NI_QTYPE_SUPTYPES, "Supported query types" },
104 { NI_QTYPE_DNSNAME, "DNS name" },
105 { NI_QTYPE_NODEADDR, "Node addresses" },
106 { NI_QTYPE_IPV4ADDR, "IPv4 node addresses" },
110 static const value_string names_rrenum_matchcode[] = {
111 { RPM_PCO_ADD, "Add" },
112 { RPM_PCO_CHANGE, "Change" },
113 { RPM_PCO_SETGLOBAL, "Set Global" },
117 static const value_string names_router_pref[] = {
118 { ND_RA_FLAG_RTPREF_HIGH, "High" },
119 { ND_RA_FLAG_RTPREF_MEDIUM, "Medium" },
120 { ND_RA_FLAG_RTPREF_LOW, "Low" },
121 { ND_RA_FLAG_RTPREF_RSV, "Reserved" },
125 dissect_contained_icmpv6(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
128 volatile address save_dl_src;
129 volatile address save_dl_dst;
130 volatile address save_net_src;
131 volatile address save_net_dst;
132 volatile address save_src;
133 volatile address save_dst;
134 gboolean save_in_error_pkt;
136 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
138 /* tiny sanity check */
139 if ((tvb_get_guint8(tvb, offset) & 0xf0) == 0x60) {
140 /* The contained packet is an IPv6 datagram; dissect it.
142 Set the columns non-writable, so that the packet list
143 shows this as an ICMPv6 packet, not as the type of packet
144 for which the ICMPv6 packet was generated. */
145 col_set_writable(pinfo->cinfo, FALSE);
147 /* Also, save the current values of the addresses, and restore
148 them when we're finished dissecting the contained packet, so
149 that the address columns in the summary don't reflect the
150 contained packet, but reflect this packet instead. */
151 save_dl_src = pinfo->dl_src;
152 save_dl_dst = pinfo->dl_dst;
153 save_net_src = pinfo->net_src;
154 save_net_dst = pinfo->net_dst;
155 save_src = pinfo->src;
156 save_dst = pinfo->dst;
158 /* Save the current value of the "we're inside an error packet"
159 flag, and set that flag; subdissectors may treat packets
160 that are the payload of error packets differently from
162 save_in_error_pkt = pinfo->in_error_pkt;
163 pinfo->in_error_pkt = TRUE;
165 /* Dissect the contained packet.
166 Catch ReportedBoundsError, and do nothing if we see it,
167 because it's not an error if the contained packet is short;
168 there's no guarantee that all of it was included.
170 XXX - should catch BoundsError, and re-throw it after cleaning
173 call_dissector(ipv6_handle, next_tvb, pinfo, tree);
175 CATCH(ReportedBoundsError) {
180 /* Restore the "we're inside an error packet" flag. */
181 pinfo->in_error_pkt = save_in_error_pkt;
183 /* Restore the addresses. */
184 pinfo->dl_src = save_dl_src;
185 pinfo->dl_dst = save_dl_dst;
186 pinfo->net_src = save_net_src;
187 pinfo->net_dst = save_net_dst;
188 pinfo->src = save_src;
189 pinfo->dst = save_dst;
191 call_dissector(data_handle,next_tvb, pinfo, tree);
195 dissect_icmpv6opt(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
197 proto_tree *icmp6opt_tree, *field_tree;
199 struct nd_opt_hdr nd_opt_hdr, *opt;
207 if ((int)tvb_reported_length(tvb) <= offset)
208 return; /* No more options left */
211 tvb_memcpy(tvb, (guint8 *)opt, offset, sizeof *opt);
212 len = opt->nd_opt_len << 3;
214 /* !!! specify length */
215 ti = proto_tree_add_text(tree, tvb, offset, len, "ICMPv6 options");
216 icmp6opt_tree = proto_item_add_subtree(ti, ett_icmpv6opt);
219 proto_tree_add_text(icmp6opt_tree, tvb,
220 offset + offsetof(struct nd_opt_hdr, nd_opt_len), 1,
221 "Invalid option length: %u",
223 return; /* we must not try to decode this */
226 switch (opt->nd_opt_type) {
227 case ND_OPT_SOURCE_LINKADDR:
228 typename = "Source link-layer address";
230 case ND_OPT_TARGET_LINKADDR:
231 typename = "Target link-layer address";
233 case ND_OPT_PREFIX_INFORMATION:
234 typename = "Prefix information";
236 case ND_OPT_REDIRECTED_HEADER:
237 typename = "Redirected header";
242 case ND_OPT_ADVINTERVAL:
243 typename = "Advertisement Interval";
245 case ND_OPT_HOMEAGENT_INFO:
246 typename = "Home Agent Information";
249 typename = "HMIPv6 MAP option";
252 typename = "Unknown";
256 proto_tree_add_text(icmp6opt_tree, tvb,
257 offset + offsetof(struct nd_opt_hdr, nd_opt_type), 1,
258 "Type: %u (%s)", opt->nd_opt_type, typename);
259 proto_tree_add_text(icmp6opt_tree, tvb,
260 offset + offsetof(struct nd_opt_hdr, nd_opt_len), 1,
261 "Length: %u bytes (%u)", opt->nd_opt_len << 3, opt->nd_opt_len);
264 switch (opt->nd_opt_type) {
265 case ND_OPT_SOURCE_LINKADDR:
266 case ND_OPT_TARGET_LINKADDR:
270 len = (opt->nd_opt_len << 3) - sizeof(*opt);
271 t = (char *)malloc(len * 3);
272 memset(t, 0, len * 3);
273 p = offset + sizeof(*opt);
274 for (i = 0; i < len; i++) {
277 sprintf(&t[i * 3], "%02x", tvb_get_guint8(tvb, p + i) & 0xff);
279 proto_tree_add_text(icmp6opt_tree, tvb,
280 offset + sizeof(*opt), len, "Link-layer address: %s", t);
284 case ND_OPT_PREFIX_INFORMATION:
286 struct nd_opt_prefix_info nd_opt_prefix_info, *pi;
289 pi = &nd_opt_prefix_info;
290 tvb_memcpy(tvb, (guint8 *)pi, offset, sizeof *pi);
291 proto_tree_add_text(icmp6opt_tree, tvb,
292 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_prefix_len),
293 1, "Prefix length: %u", pi->nd_opt_pi_prefix_len);
295 flagoff = offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_flags_reserved);
296 tf = proto_tree_add_text(icmp6opt_tree, tvb, flagoff, 1, "Flags: 0x%02x",
297 tvb_get_guint8(tvb, offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_flags_reserved)));
298 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
299 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
300 decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
301 ND_OPT_PI_FLAG_ONLINK, 8, "Onlink", "Not onlink"));
302 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
303 decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
304 ND_OPT_PI_FLAG_AUTO, 8, "Auto", "Not auto"));
305 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
306 decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
307 ND_OPT_PI_FLAG_ROUTER, 8,
308 "Router Address", "Not router address"));
309 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
310 decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
311 ND_OPT_PI_FLAG_SITEPREF, 8,
312 "Site prefix", "Not site prefix"));
313 proto_tree_add_text(icmp6opt_tree, tvb,
314 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_valid_time),
315 4, "Valid lifetime: 0x%08x",
316 pntohl(&pi->nd_opt_pi_valid_time));
317 proto_tree_add_text(icmp6opt_tree, tvb,
318 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_preferred_time),
319 4, "Preferred lifetime: 0x%08x",
320 pntohl(&pi->nd_opt_pi_preferred_time));
321 proto_tree_add_text(icmp6opt_tree, tvb,
322 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_prefix),
323 16, "Prefix: %s", ip6_to_str(&pi->nd_opt_pi_prefix));
326 case ND_OPT_REDIRECTED_HEADER:
327 proto_tree_add_text(icmp6opt_tree, tvb,
328 offset + 8, (opt->nd_opt_len << 3) - 8, "Redirected packet");
329 dissect_contained_icmpv6(tvb, offset + 8, pinfo, icmp6opt_tree);
332 proto_tree_add_text(icmp6opt_tree, tvb,
333 offset + offsetof(struct nd_opt_mtu, nd_opt_mtu_mtu), 4,
334 "MTU: %u", tvb_get_ntohl(tvb, offset + offsetof(struct nd_opt_mtu, nd_opt_mtu_mtu)));
336 case ND_OPT_ADVINTERVAL:
337 proto_tree_add_text(icmp6opt_tree, tvb,
338 offset + offsetof(struct nd_opt_adv_int, nd_opt_adv_int_advint), 4,
339 "Advertisement Interval: %u",
340 tvb_get_ntohl(tvb, offset + offsetof(struct nd_opt_adv_int, nd_opt_adv_int_advint)));
342 case ND_OPT_HOMEAGENT_INFO:
344 struct nd_opt_ha_info pibuf, *pi;
347 tvb_memcpy(tvb, (guint8 *)pi, offset, sizeof *pi);
348 proto_tree_add_text(icmp6opt_tree, tvb,
349 offset + offsetof(struct nd_opt_ha_info, nd_opt_ha_info_ha_pref),
350 2, "Home Agent Preference: %d",
351 (gint16)pntohs(&pi->nd_opt_ha_info_ha_pref));
352 proto_tree_add_text(icmp6opt_tree, tvb,
353 offset + offsetof(struct nd_opt_ha_info, nd_opt_ha_info_ha_life),
354 2, "Home Agent Lifetime: %u",
355 pntohs(&pi->nd_opt_ha_info_ha_life));
360 struct nd_opt_map_info mapbuf, *map;
364 tvb_memcpy(tvb, (guint8 *)map, offset, sizeof *map);
365 proto_tree_add_text(icmp6opt_tree, tvb,
366 offset + offsetof(struct nd_opt_map_info, nd_opt_map_dist_and_pref),
367 1, "Distance: %u", (map->nd_opt_map_dist_and_pref >> 4));
368 proto_tree_add_text(icmp6opt_tree, tvb,
369 offset + offsetof(struct nd_opt_map_info, nd_opt_map_dist_and_pref),
370 1, "Preference: %u", (map->nd_opt_map_dist_and_pref & 0x0F));
371 flagoff = offset + offsetof(struct nd_opt_map_info,
373 tf = proto_tree_add_text(icmp6opt_tree, tvb, flagoff, 1,
375 tvb_get_guint8(tvb, offset + offsetof(struct nd_opt_map_info,
377 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
378 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
379 decode_boolean_bitfield(map->nd_opt_map_flags,
380 ND_OPT_MAP_FLAG_R, 8, "R", "No R"));
381 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
382 decode_boolean_bitfield(map->nd_opt_map_flags,
383 ND_OPT_MAP_FLAG_M, 8, "M", "No M"));
384 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
385 decode_boolean_bitfield(map->nd_opt_map_flags,
386 ND_OPT_MAP_FLAG_I, 8, "I", "No I"));
387 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
388 decode_boolean_bitfield(map->nd_opt_map_flags,
389 ND_OPT_MAP_FLAG_T, 8, "T", "No T"));
390 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
391 decode_boolean_bitfield(map->nd_opt_map_flags,
392 ND_OPT_MAP_FLAG_P, 8, "P", "No P"));
393 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
394 decode_boolean_bitfield(map->nd_opt_map_flags,
395 ND_OPT_MAP_FLAG_V, 8, "V", "No V"));
396 proto_tree_add_text(icmp6opt_tree, tvb,
397 offset + offsetof(struct nd_opt_map_info, nd_opt_map_lifetime),
398 4, "Lifetime: %u", pntohl(&map->nd_opt_map_lifetime));
400 proto_tree_add_text(icmp6opt_tree, tvb,
401 offset + offsetof(struct nd_opt_map_info, nd_opt_map_address), 16,
403 "Address of MAP: %s (%s)",
404 get_hostname6(&map->nd_opt_map_address),
406 "Address of MAP: %s",
408 ip6_to_str(&map->nd_opt_map_address));
411 case ND_OPT_ROUTE_INFO:
413 struct nd_opt_route_info ribuf, *ri;
414 struct e_in6_addr in6;
419 tvb_memcpy(tvb, (guint8 *)ri, offset, sizeof *ri);
420 memset(&in6, 0, sizeof(in6));
421 switch (ri->nd_opt_rti_len) {
426 tvb_memcpy(tvb, (guint8 *)&in6, offset + sizeof(*ri), l = 8);
429 tvb_memcpy(tvb, (guint8 *)&in6, offset + sizeof(*ri), l = 16);
436 proto_tree_add_text(icmp6opt_tree, tvb,
437 offset + offsetof(struct nd_opt_route_info, nd_opt_rti_prefixlen),
438 1, "Prefix length: %u", ri->nd_opt_rti_prefixlen);
439 tf = proto_tree_add_text(icmp6opt_tree, tvb,
440 offset + offsetof(struct nd_opt_route_info, nd_opt_rti_flags),
441 1, "Flags: 0x%02x", ri->nd_opt_rti_flags);
442 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
443 proto_tree_add_text(field_tree, tvb,
444 offset + offsetof(struct nd_opt_route_info, nd_opt_rti_flags),
446 decode_enumerated_bitfield(ri->nd_opt_rti_flags,
447 ND_RA_FLAG_RTPREF_MASK, 8, names_router_pref,
448 "Router preference: %s"));
449 lifetime = pntohl(&ri->nd_opt_rti_lifetime);
450 if (lifetime == 0xffffffff)
451 proto_tree_add_text(icmp6opt_tree, tvb,
452 offset + offsetof(struct nd_opt_route_info, nd_opt_rti_lifetime),
453 sizeof(ri->nd_opt_rti_lifetime), "Lifetime: infinity");
455 proto_tree_add_text(icmp6opt_tree, tvb,
456 offset + offsetof(struct nd_opt_route_info, nd_opt_rti_lifetime),
457 sizeof(ri->nd_opt_rti_lifetime), "Lifetime: %u", lifetime);
458 proto_tree_add_text(icmp6opt_tree, tvb,
459 offset + sizeof(*ri), l, "Prefix: %s", ip6_to_str(&in6));
461 proto_tree_add_text(icmp6opt_tree, tvb,
462 offset + offsetof(struct nd_opt_hdr, nd_opt_len), 1,
463 "Invalid option length: %u", opt->nd_opt_len);
469 offset += (opt->nd_opt_len << 3);
474 * draft-ietf-ipngwg-icmp-name-lookups-07.txt
475 * Note that the packet format was changed several times in the past.
479 bitrange0(v, s, buf, buflen)
499 ep = buf + buflen - 1;
500 memset(buf, 0, buflen);
503 /* shift till we have 0x01 */
504 if ((v & 0x01) == 0) {
507 v >>= 4; off += 4; continue;
509 v >>= 3; off += 3; continue;
510 case 0x04: case 0x0c:
511 v >>= 2; off += 2; continue;
513 v >>= 1; off += 1; continue;
517 /* we have 0x01 with us */
518 for (i = 0; i < 32 - off; i++) {
519 if ((v & (0x01 << i)) == 0)
523 l = snprintf(p, ep - p, ",%d", s + off);
525 l = snprintf(p, ep - p, ",%d-%d", s + off,
528 if (l == -1 || l > ep - p) {
539 bitrange(tvbuff_t *tvb, int offset, int l, int s)
541 static char buf[1024];
545 memset(buf, 0, sizeof(buf));
547 eq = buf + sizeof(buf) - 1;
548 for (i = 0; i < l; i++) {
549 if (bitrange0(tvb_get_ntohl(tvb, offset + i * 4), s + i * 4, q, eq - q) == NULL) {
550 if (q != buf && q + 5 < buf + sizeof(buf))
551 strncpy(q, ",...", 5);
560 dissect_nodeinfo(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
562 proto_tree *field_tree;
564 struct icmp6_nodeinfo icmp6_nodeinfo, *ni;
569 char dname[MAXDNAME];
572 ni = &icmp6_nodeinfo;
573 tvb_memcpy(tvb, (guint8 *)ni, offset, sizeof *ni);
575 flags = pntohs(&ni->ni_flags);
576 tf = proto_tree_add_text(tree, tvb,
577 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
578 sizeof(ni->ni_flags), "Flags: 0x%04x", flags);
579 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_flag);
580 switch (pntohs(&ni->ni_qtype)) {
581 case NI_QTYPE_SUPTYPES:
582 if (ni->ni_type == ICMP6_NI_QUERY) {
583 proto_tree_add_text(field_tree, tvb,
584 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
585 sizeof(ni->ni_flags), "%s",
586 decode_boolean_bitfield(flags, NI_SUPTYPE_FLAG_COMPRESS, sizeof(flags) * 8,
587 "Compressed reply supported",
588 "No compressed reply support"));
590 proto_tree_add_text(field_tree, tvb,
591 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
592 sizeof(ni->ni_flags), "%s",
593 decode_boolean_bitfield(flags, NI_SUPTYPE_FLAG_COMPRESS, sizeof(flags) * 8,
594 "Compressed", "Not compressed"));
597 case NI_QTYPE_DNSNAME:
598 if (ni->ni_type == ICMP6_NI_REPLY) {
599 proto_tree_add_text(field_tree, tvb,
600 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
601 sizeof(ni->ni_flags), "%s",
602 decode_boolean_bitfield(flags, NI_FQDN_FLAG_VALIDTTL, sizeof(flags) * 8,
603 "Valid TTL field", "Meaningless TTL field"));
606 case NI_QTYPE_NODEADDR:
607 proto_tree_add_text(field_tree, tvb,
608 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
609 sizeof(ni->ni_flags), "%s",
610 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_GLOBAL, sizeof(flags) * 8,
612 "Not global address"));
613 proto_tree_add_text(field_tree, tvb,
614 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
615 sizeof(ni->ni_flags), "%s",
616 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_SITELOCAL, sizeof(flags) * 8,
617 "Site-local address",
618 "Not site-local address"));
619 proto_tree_add_text(field_tree, tvb,
620 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
621 sizeof(ni->ni_flags), "%s",
622 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_LINKLOCAL, sizeof(flags) * 8,
623 "Link-local address",
624 "Not link-local address"));
625 proto_tree_add_text(field_tree, tvb,
626 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
627 sizeof(ni->ni_flags), "%s",
628 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_COMPAT, sizeof(flags) * 8,
629 "IPv4 compatible/mapped address",
630 "Not IPv4 compatible/mapped address"));
632 case NI_QTYPE_IPV4ADDR:
633 proto_tree_add_text(field_tree, tvb,
634 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
635 sizeof(ni->ni_flags), "%s",
636 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_ALL, sizeof(flags) * 8,
637 "All unicast address",
638 "Unicast addresses on the queried interface"));
639 proto_tree_add_text(field_tree, tvb,
640 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
641 sizeof(ni->ni_flags), "%s",
642 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_TRUNCATE, sizeof(flags) * 8,
643 "Truncated", "Not truncated"));
648 proto_tree_add_text(tree, tvb,
649 offset + offsetof(struct icmp6_nodeinfo, icmp6_ni_nonce[0]),
650 sizeof(ni->icmp6_ni_nonce), "Nonce: 0x%08x%08x",
651 pntohl(&ni->icmp6_ni_nonce[0]), pntohl(&ni->icmp6_ni_nonce[4]));
653 /* offset for "the rest of data" */
657 if (!tvb_bytes_exist(tvb, offset, sizeof(*ni)))
659 if (ni->ni_type == ICMP6_NI_QUERY) {
660 switch (ni->ni_code) {
661 case ICMP6_NI_SUBJ_IPV6:
662 n = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
663 n /= sizeof(struct e_in6_addr);
664 tf = proto_tree_add_text(tree, tvb,
665 offset + sizeof(*ni), -1, "IPv6 subject addresses");
666 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_subject6);
667 p = offset + sizeof *ni;
668 for (i = 0; i < n; i++) {
669 struct e_in6_addr e_in6_addr;
670 tvb_memcpy(tvb, (guint8 *)&e_in6_addr, p, sizeof e_in6_addr);
671 proto_tree_add_text(field_tree, tvb,
672 p, sizeof(struct e_in6_addr),
673 "%s", ip6_to_str(&e_in6_addr));
674 p += sizeof(struct e_in6_addr);
676 off = tvb_length_remaining(tvb, offset);
678 case ICMP6_NI_SUBJ_FQDN:
679 l = get_dns_name(tvb, offset + sizeof(*ni),
680 offset + sizeof(*ni), dname, sizeof(dname));
681 if (tvb_bytes_exist(tvb, offset + sizeof(*ni) + l, 1) &&
682 tvb_get_guint8(tvb, offset + sizeof(*ni) + l) == 0) {
684 proto_tree_add_text(tree, tvb, offset + sizeof(*ni), l,
685 "DNS label: %s (truncated)", dname);
687 proto_tree_add_text(tree, tvb, offset + sizeof(*ni), l,
688 "DNS label: %s", dname);
690 off = tvb_length_remaining(tvb, offset + sizeof(*ni) + l);
692 case ICMP6_NI_SUBJ_IPV4:
693 n = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
694 n /= sizeof(guint32);
695 tf = proto_tree_add_text(tree, tvb,
696 offset + sizeof(*ni), -1, "IPv4 subject addresses");
697 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_subject4);
698 p = offset + sizeof *ni;
699 for (i = 0; i < n; i++) {
700 tvb_memcpy(tvb, ipaddr, p, 4);
701 proto_tree_add_text(field_tree, tvb,
702 p, sizeof(guint32), "%s", ip_to_str(ipaddr));
703 p += sizeof(guint32);
705 off = tvb_length_remaining(tvb, offset);
709 switch (pntohs(&ni->ni_qtype)) {
712 case NI_QTYPE_SUPTYPES:
713 p = offset + sizeof *ni;
714 tf = proto_tree_add_text(tree, tvb,
715 offset + sizeof(*ni), -1,
716 "Supported type bitmap%s",
717 (flags & 0x0001) ? ", compressed" : "");
718 field_tree = proto_item_add_subtree(tf,
719 ett_nodeinfo_nodebitmap);
721 while (tvb_bytes_exist(tvb, p, sizeof(guint32))) { /* XXXX Check what? */
722 if ((flags & 0x0001) == 0) {
723 l = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
724 l /= sizeof(guint32);
727 l = tvb_get_ntohs(tvb, p);
728 i = tvb_get_ntohs(tvb, p + sizeof(guint16)); /*skip*/
730 if (n + l * 32 > (1 << 16))
732 if (n + (l + i) * 32 > (1 << 16))
734 if ((flags & 0x0001) == 0) {
735 proto_tree_add_text(field_tree, tvb, p,
736 l * 4, "Bitmap (%d to %d): %s", n, n + l * 32 - 1,
737 bitrange(tvb, p, l, n));
740 proto_tree_add_text(field_tree, tvb, p,
741 4 + l * 4, "Bitmap (%d to %d): %s", n, n + l * 32 - 1,
742 bitrange(tvb, p + 4, l, n));
745 n += l * 32 + i * 32;
747 off = tvb_length_remaining(tvb, offset);
749 case NI_QTYPE_DNSNAME:
750 proto_tree_add_text(tree, tvb, offset + sizeof(*ni),
751 sizeof(gint32), "TTL: %d", (gint32)tvb_get_ntohl(tvb, offset + sizeof *ni));
752 tf = proto_tree_add_text(tree, tvb,
753 offset + sizeof(*ni) + sizeof(guint32), -1,
755 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_nodedns);
756 j = offset + sizeof (*ni) + sizeof(guint32);
757 while (j < tvb_reported_length(tvb)) {
758 l = get_dns_name(tvb, j,
759 offset + sizeof (*ni) + sizeof(guint32),
760 dname,sizeof(dname));
761 if (tvb_bytes_exist(tvb, j + l, 1) &&
762 tvb_get_guint8(tvb, j + l) == 0) {
764 proto_tree_add_text(field_tree, tvb, j, l,
765 "DNS label: %s (truncated)", dname);
767 proto_tree_add_text(field_tree, tvb, j, l,
768 "DNS label: %s", dname);
772 off = tvb_length_remaining(tvb, offset);
774 case NI_QTYPE_NODEADDR:
775 n = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
776 n /= sizeof(gint32) + sizeof(struct e_in6_addr);
777 tf = proto_tree_add_text(tree, tvb,
778 offset + sizeof(*ni), -1, "IPv6 node addresses");
779 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_node6);
780 p = offset + sizeof (*ni);
781 for (i = 0; i < n; i++) {
782 struct e_in6_addr e_in6_addr;
784 ttl = (gint32)tvb_get_ntohl(tvb, p);
785 tvb_memcpy(tvb, (guint8 *)&e_in6_addr, p + sizeof ttl, sizeof e_in6_addr);
786 proto_tree_add_text(field_tree, tvb,
787 p, sizeof(struct e_in6_addr) + sizeof(gint32),
788 "%s (TTL %d)", ip6_to_str(&e_in6_addr), ttl);
789 p += sizeof(struct e_in6_addr) + sizeof(gint32);
791 off = tvb_length_remaining(tvb, offset);
793 case NI_QTYPE_IPV4ADDR:
794 n = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
795 n /= sizeof(gint32) + sizeof(guint32);
796 tf = proto_tree_add_text(tree, tvb,
797 offset + sizeof(*ni), -1, "IPv4 node addresses");
798 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_node4);
799 p = offset + sizeof *ni;
800 for (i = 0; i < n; i++) {
801 tvb_memcpy(tvb, ipaddr, sizeof(gint32) + p, 4);
802 proto_tree_add_text(field_tree, tvb,
803 p, sizeof(guint32), "%s (TTL %d)", ip_to_str(ipaddr), tvb_get_ntohl(tvb, p));
804 p += sizeof(gint32) + sizeof(guint32);
806 off = tvb_length_remaining(tvb, offset);
812 /* the rest of data */
813 call_dissector(data_handle,tvb_new_subset(tvb, offset + off, -1, -1), pinfo, tree);
817 dissect_rrenum(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
819 proto_tree *field_tree, *opt_tree;
821 struct icmp6_router_renum icmp6_router_renum, *rr;
822 struct rr_pco_match rr_pco_match, *match;
823 struct rr_pco_use rr_pco_use, *use;
828 rr = &icmp6_router_renum;
829 tvb_memcpy(tvb, (guint8 *)rr, offset, sizeof *rr);
830 proto_tree_add_text(tree, tvb,
831 offset + offsetof(struct icmp6_router_renum, rr_seqnum), 4,
832 "Sequence number: 0x%08x", pntohl(&rr->rr_seqnum));
833 proto_tree_add_text(tree, tvb,
834 offset + offsetof(struct icmp6_router_renum, rr_segnum), 1,
835 "Segment number: 0x%02x", rr->rr_segnum);
837 flagoff = offset + offsetof(struct icmp6_router_renum, rr_flags);
838 flags = tvb_get_guint8(tvb, flagoff);
839 tf = proto_tree_add_text(tree, tvb, flagoff, 1,
840 "Flags: 0x%02x", flags);
841 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
842 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
843 decode_boolean_bitfield(flags, 0x80, 8,
844 "Test command", "Not test command"));
845 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
846 decode_boolean_bitfield(flags, 0x40, 8,
847 "Result requested", "Result not requested"));
848 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
849 decode_boolean_bitfield(flags, 0x20, 8,
850 "All interfaces", "Not all interfaces"));
851 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
852 decode_boolean_bitfield(flags, 0x10, 8,
853 "Site specific", "Not site specific"));
854 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
855 decode_boolean_bitfield(flags, 0x08, 8,
856 "Processed previously", "Complete result"));
858 proto_tree_add_text(tree, tvb,
859 offset + offsetof(struct icmp6_router_renum, rr_maxdelay), 2,
860 "Max delay: 0x%04x", pntohs(&rr->rr_maxdelay));
861 call_dissector(data_handle,tvb_new_subset(tvb, offset + sizeof(*rr), -1, -1), pinfo, tree); /*XXX*/
863 if (rr->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) {
864 off = offset + sizeof(*rr);
865 match = &rr_pco_match;
866 tvb_memcpy(tvb, (guint8 *)match, off, sizeof *match);
867 tf = proto_tree_add_text(tree, tvb, off, sizeof(*match),
868 "Match-Prefix: %s/%u (%u-%u)", ip6_to_str(&match->rpm_prefix),
869 match->rpm_matchlen, match->rpm_minlen, match->rpm_maxlen);
870 opt_tree = proto_item_add_subtree(tf, ett_icmpv6opt);
871 proto_tree_add_text(opt_tree, tvb,
872 off + offsetof(struct rr_pco_match, rpm_code),
873 sizeof(match->rpm_code), "OpCode: %s (%u)",
874 val_to_str(match->rpm_code, names_rrenum_matchcode, "Unknown"),
876 proto_tree_add_text(opt_tree, tvb,
877 off + offsetof(struct rr_pco_match, rpm_len),
878 sizeof(match->rpm_len), "OpLength: %u (%u octets)",
879 match->rpm_len, match->rpm_len * 8);
880 proto_tree_add_text(opt_tree, tvb,
881 off + offsetof(struct rr_pco_match, rpm_ordinal),
882 sizeof(match->rpm_ordinal), "Ordinal: %u", match->rpm_ordinal);
883 proto_tree_add_text(opt_tree, tvb,
884 off + offsetof(struct rr_pco_match, rpm_matchlen),
885 sizeof(match->rpm_matchlen), "MatchLen: %u", match->rpm_matchlen);
886 proto_tree_add_text(opt_tree, tvb,
887 off + offsetof(struct rr_pco_match, rpm_minlen),
888 sizeof(match->rpm_minlen), "MinLen: %u", match->rpm_minlen);
889 proto_tree_add_text(opt_tree, tvb,
890 off + offsetof(struct rr_pco_match, rpm_maxlen),
891 sizeof(match->rpm_maxlen), "MaxLen: %u", match->rpm_maxlen);
892 proto_tree_add_text(opt_tree, tvb,
893 off + offsetof(struct rr_pco_match, rpm_prefix),
894 sizeof(match->rpm_prefix), "MatchPrefix: %s",
895 ip6_to_str(&match->rpm_prefix));
897 off += sizeof(*match);
899 for (l = match->rpm_len * 8 - sizeof(*match);
900 l >= sizeof(*use); l -= sizeof(*use), off += sizeof(*use)) {
901 tvb_memcpy(tvb, (guint8 *)use, off, sizeof *use);
902 tf = proto_tree_add_text(tree, tvb, off, sizeof(*use),
903 "Use-Prefix: %s/%u (keep %u)", ip6_to_str(&use->rpu_prefix),
904 use->rpu_uselen, use->rpu_keeplen);
905 opt_tree = proto_item_add_subtree(tf, ett_icmpv6opt);
906 proto_tree_add_text(opt_tree, tvb,
907 off + offsetof(struct rr_pco_use, rpu_uselen),
908 sizeof(use->rpu_uselen), "UseLen: %u", use->rpu_uselen);
909 proto_tree_add_text(opt_tree, tvb,
910 off + offsetof(struct rr_pco_use, rpu_keeplen),
911 sizeof(use->rpu_keeplen), "KeepLen: %u", use->rpu_keeplen);
912 tf = proto_tree_add_text(opt_tree, tvb,
913 flagoff = off + offsetof(struct rr_pco_use, rpu_ramask),
914 sizeof(use->rpu_ramask), "FlagMask: 0x%x", use->rpu_ramask);
915 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
916 flags = tvb_get_guint8(tvb, flagoff);
917 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
918 decode_boolean_bitfield(flags,
919 ICMP6_RR_PCOUSE_RAFLAGS_ONLINK, 8,
920 "Onlink", "Not onlink"));
921 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
922 decode_boolean_bitfield(flags,
923 ICMP6_RR_PCOUSE_RAFLAGS_AUTO, 8,
924 "Auto", "Not auto"));
925 tf = proto_tree_add_text(opt_tree, tvb,
926 flagoff = off + offsetof(struct rr_pco_use, rpu_raflags),
927 sizeof(use->rpu_raflags), "RAFlags: 0x%x", use->rpu_raflags);
928 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
929 flags = tvb_get_guint8(tvb, flagoff);
930 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
931 decode_boolean_bitfield(flags,
932 ICMP6_RR_PCOUSE_RAFLAGS_ONLINK, 8,
933 "Onlink", "Not onlink"));
934 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
935 decode_boolean_bitfield(flags,
936 ICMP6_RR_PCOUSE_RAFLAGS_AUTO, 8, "Auto", "Not auto"));
937 if (pntohl(&use->rpu_vltime) == 0xffffffff)
938 proto_tree_add_text(opt_tree, tvb,
939 off + offsetof(struct rr_pco_use, rpu_vltime),
940 sizeof(use->rpu_vltime), "Valid Lifetime: infinity");
942 proto_tree_add_text(opt_tree, tvb,
943 off + offsetof(struct rr_pco_use, rpu_vltime),
944 sizeof(use->rpu_vltime), "Valid Lifetime: %u",
945 pntohl(&use->rpu_vltime));
946 if (pntohl(&use->rpu_pltime) == 0xffffffff)
947 proto_tree_add_text(opt_tree, tvb,
948 off + offsetof(struct rr_pco_use, rpu_pltime),
949 sizeof(use->rpu_pltime), "Preferred Lifetime: infinity");
951 proto_tree_add_text(opt_tree, tvb,
952 off + offsetof(struct rr_pco_use, rpu_pltime),
953 sizeof(use->rpu_pltime), "Preferred Lifetime: %u",
954 pntohl(&use->rpu_pltime));
955 tf = proto_tree_add_text(opt_tree, tvb,
956 flagoff = off + offsetof(struct rr_pco_use, rpu_flags),
957 sizeof(use->rpu_flags), "Flags: 0x%08x",
958 pntohl(&use->rpu_flags));
959 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
960 flags = tvb_get_guint8(tvb, flagoff);
961 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
962 decode_boolean_bitfield(flags,
963 ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, 32,
964 "Decrement valid lifetime", "No decrement valid lifetime"));
965 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
966 decode_boolean_bitfield(flags,
967 ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, 32,
968 "Decrement preferred lifetime",
969 "No decrement preferred lifetime"));
970 proto_tree_add_text(opt_tree, tvb,
971 off + offsetof(struct rr_pco_use, rpu_prefix),
972 sizeof(use->rpu_prefix), "UsePrefix: %s",
973 ip6_to_str(&use->rpu_prefix));
980 dissect_icmpv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
982 proto_tree *icmp6_tree, *field_tree;
983 proto_item *ti, *tf = NULL;
984 struct icmp6_hdr icmp6_hdr, *dp;
985 struct icmp6_nodeinfo *ni = NULL;
986 char *codename, *typename;
987 char *colcodename, *coltypename;
989 guint length, reported_length;
992 guint16 cksum, computed_cksum;
996 if (check_col(pinfo->cinfo, COL_PROTOCOL))
997 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ICMPv6");
998 if (check_col(pinfo->cinfo, COL_INFO))
999 col_clear(pinfo->cinfo, COL_INFO);
1002 tvb_memcpy(tvb, (guint8 *)&icmp6_hdr, offset, sizeof icmp6_hdr);
1004 codename = typename = colcodename = coltypename = "Unknown";
1006 switch (dp->icmp6_type) {
1007 case ICMP6_DST_UNREACH:
1008 typename = coltypename = "Unreachable";
1009 switch (dp->icmp6_code) {
1010 case ICMP6_DST_UNREACH_NOROUTE:
1011 codename = colcodename = "Route unreachable";
1013 case ICMP6_DST_UNREACH_ADMIN:
1014 codename = colcodename = "Administratively prohibited";
1016 case ICMP6_DST_UNREACH_NOTNEIGHBOR:
1017 codename = colcodename = "Not a neighbor";
1019 case ICMP6_DST_UNREACH_ADDR:
1020 codename = colcodename = "Address unreachable";
1022 case ICMP6_DST_UNREACH_NOPORT:
1023 codename = colcodename = "Port unreachable";
1027 case ICMP6_PACKET_TOO_BIG:
1028 typename = coltypename = "Too big";
1029 codename = colcodename = NULL;
1031 case ICMP6_TIME_EXCEEDED:
1032 typename = coltypename = "Time exceeded";
1033 switch (dp->icmp6_code) {
1034 case ICMP6_TIME_EXCEED_TRANSIT:
1035 codename = colcodename = "In-transit";
1037 case ICMP6_TIME_EXCEED_REASSEMBLY:
1038 codename = colcodename = "Reassembly";
1042 case ICMP6_PARAM_PROB:
1043 typename = coltypename = "Parameter problem";
1044 switch (dp->icmp6_code) {
1045 case ICMP6_PARAMPROB_HEADER:
1046 codename = colcodename = "Header";
1048 case ICMP6_PARAMPROB_NEXTHEADER:
1049 codename = colcodename = "Next header";
1051 case ICMP6_PARAMPROB_OPTION:
1052 codename = colcodename = "Option";
1056 case ICMP6_ECHO_REQUEST:
1057 typename = coltypename = "Echo request";
1058 codename = colcodename = NULL;
1060 case ICMP6_ECHO_REPLY:
1061 typename = coltypename = "Echo reply";
1062 codename = colcodename = NULL;
1064 case ICMP6_MEMBERSHIP_QUERY:
1065 typename = coltypename = "Multicast listener query";
1066 codename = colcodename = NULL;
1068 case ICMP6_MEMBERSHIP_REPORT:
1069 typename = coltypename = "Multicast listener report";
1070 codename = colcodename = NULL;
1072 case ICMP6_MEMBERSHIP_REDUCTION:
1073 typename = coltypename = "Multicast listener done";
1074 codename = colcodename = NULL;
1076 case ND_ROUTER_SOLICIT:
1077 typename = coltypename = "Router solicitation";
1078 codename = colcodename = NULL;
1079 len = sizeof(struct nd_router_solicit);
1081 case ND_ROUTER_ADVERT:
1082 typename = coltypename = "Router advertisement";
1083 codename = colcodename = NULL;
1084 len = sizeof(struct nd_router_advert);
1086 case ND_NEIGHBOR_SOLICIT:
1087 typename = coltypename = "Neighbor solicitation";
1088 codename = colcodename = NULL;
1089 len = sizeof(struct nd_neighbor_solicit);
1091 case ND_NEIGHBOR_ADVERT:
1092 typename = coltypename = "Neighbor advertisement";
1093 codename = colcodename = NULL;
1094 len = sizeof(struct nd_neighbor_advert);
1097 typename = coltypename = "Redirect";
1098 codename = colcodename = NULL;
1099 len = sizeof(struct nd_redirect);
1101 case ICMP6_ROUTER_RENUMBERING:
1102 typename = coltypename = "Router renumbering";
1103 switch (dp->icmp6_code) {
1104 case ICMP6_ROUTER_RENUMBERING_COMMAND:
1105 codename = colcodename = "Command";
1107 case ICMP6_ROUTER_RENUMBERING_RESULT:
1108 codename = colcodename = "Result";
1110 case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
1111 codename = colcodename = "Sequence number reset";
1114 len = sizeof(struct icmp6_router_renum);
1116 case ICMP6_NI_QUERY:
1117 case ICMP6_NI_REPLY:
1118 ni = (struct icmp6_nodeinfo *)dp;
1119 if (ni->ni_type == ICMP6_NI_QUERY) {
1120 typename = coltypename = "Node information query";
1121 switch (ni->ni_code) {
1122 case ICMP6_NI_SUBJ_IPV6:
1123 codename = "Query subject = IPv6 addresses";
1125 case ICMP6_NI_SUBJ_FQDN:
1126 if (tvb_bytes_exist(tvb, offset, sizeof(*ni)))
1127 codename = "Query subject = DNS name";
1129 codename = "Query subject = empty";
1131 case ICMP6_NI_SUBJ_IPV4:
1132 codename = "Query subject = IPv4 addresses";
1136 typename = coltypename = "Node information reply";
1137 switch (ni->ni_code) {
1138 case ICMP6_NI_SUCCESS:
1139 codename = "Successful";
1141 case ICMP6_NI_REFUSED:
1142 codename = "Refused";
1144 case ICMP6_NI_UNKNOWN:
1145 codename = "Unknown query type";
1149 colcodename = val_to_str(pntohs(&ni->ni_qtype), names_nodeinfo_qtype,
1151 len = sizeof(struct icmp6_nodeinfo);
1155 if (check_col(pinfo->cinfo, COL_INFO)) {
1156 char typebuf[256], codebuf[256];
1158 if (coltypename && strcmp(coltypename, "Unknown") == 0) {
1159 snprintf(typebuf, sizeof(typebuf), "Unknown (0x%02x)",
1161 coltypename = typebuf;
1163 if (colcodename && strcmp(colcodename, "Unknown") == 0) {
1164 snprintf(codebuf, sizeof(codebuf), "Unknown (0x%02x)",
1166 colcodename = codebuf;
1169 col_add_fstr(pinfo->cinfo, COL_INFO, "%s (%s)", coltypename, colcodename);
1171 col_add_fstr(pinfo->cinfo, COL_INFO, "%s", coltypename);
1176 /* !!! specify length */
1177 ti = proto_tree_add_item(tree, proto_icmpv6, tvb, offset, len, FALSE);
1178 icmp6_tree = proto_item_add_subtree(ti, ett_icmpv6);
1180 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_type, tvb,
1181 offset + offsetof(struct icmp6_hdr, icmp6_type), 1,
1183 "Type: %u (%s)", dp->icmp6_type, typename);
1185 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_code, tvb,
1186 offset + offsetof(struct icmp6_hdr, icmp6_code), 1,
1188 "Code: %u (%s)", dp->icmp6_code, codename);
1190 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_code, tvb,
1191 offset + offsetof(struct icmp6_hdr, icmp6_code), 1,
1193 "Code: %u", dp->icmp6_code);
1195 cksum = (guint16)htons(dp->icmp6_cksum);
1196 length = tvb_length(tvb);
1197 reported_length = tvb_reported_length(tvb);
1198 if (!pinfo->fragmented && length >= reported_length) {
1199 /* The packet isn't part of a fragmented datagram and isn't
1200 truncated, so we can checksum it. */
1202 /* Set up the fields of the pseudo-header. */
1203 cksum_vec[0].ptr = pinfo->src.data;
1204 cksum_vec[0].len = pinfo->src.len;
1205 cksum_vec[1].ptr = pinfo->dst.data;
1206 cksum_vec[1].len = pinfo->dst.len;
1207 cksum_vec[2].ptr = (const guint8 *)&phdr;
1208 phdr[0] = htonl(tvb_reported_length(tvb));
1209 phdr[1] = htonl(IP_PROTO_ICMPV6);
1210 cksum_vec[2].len = 8;
1211 cksum_vec[3].len = tvb_reported_length(tvb);
1212 cksum_vec[3].ptr = tvb_get_ptr(tvb, offset, cksum_vec[3].len);
1213 computed_cksum = in_cksum(cksum_vec, 4);
1214 if (computed_cksum == 0) {
1215 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_checksum,
1217 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1219 "Checksum: 0x%04x (correct)", cksum);
1221 proto_tree_add_boolean_hidden(icmp6_tree, hf_icmpv6_checksum_bad,
1223 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1225 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_checksum,
1227 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1229 "Checksum: 0x%04x (incorrect, should be 0x%04x)",
1230 cksum, in_cksum_shouldbe(cksum, computed_cksum));
1233 proto_tree_add_uint(icmp6_tree, hf_icmpv6_checksum, tvb,
1234 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1239 switch (dp->icmp6_type) {
1240 case ICMP6_DST_UNREACH:
1241 case ICMP6_TIME_EXCEEDED:
1242 dissect_contained_icmpv6(tvb, offset + sizeof(*dp), pinfo,
1245 case ICMP6_PACKET_TOO_BIG:
1246 proto_tree_add_text(icmp6_tree, tvb,
1247 offset + offsetof(struct icmp6_hdr, icmp6_mtu), 4,
1248 "MTU: %u", pntohl(&dp->icmp6_mtu));
1249 dissect_contained_icmpv6(tvb, offset + sizeof(*dp), pinfo,
1252 case ICMP6_PARAM_PROB:
1253 proto_tree_add_text(icmp6_tree, tvb,
1254 offset + offsetof(struct icmp6_hdr, icmp6_pptr), 4,
1255 "Problem pointer: 0x%04x", pntohl(&dp->icmp6_pptr));
1256 dissect_contained_icmpv6(tvb, offset + sizeof(*dp), pinfo,
1259 case ICMP6_ECHO_REQUEST:
1260 case ICMP6_ECHO_REPLY:
1261 proto_tree_add_text(icmp6_tree, tvb,
1262 offset + offsetof(struct icmp6_hdr, icmp6_id), 2,
1263 "ID: 0x%04x", (guint16)ntohs(dp->icmp6_id));
1264 proto_tree_add_text(icmp6_tree, tvb,
1265 offset + offsetof(struct icmp6_hdr, icmp6_seq), 2,
1266 "Sequence: 0x%04x", (guint16)ntohs(dp->icmp6_seq));
1267 next_tvb = tvb_new_subset(tvb, offset + sizeof(*dp), -1, -1);
1268 call_dissector(data_handle,next_tvb, pinfo, icmp6_tree);
1270 case ICMP6_MEMBERSHIP_QUERY:
1271 case ICMP6_MEMBERSHIP_REPORT:
1272 case ICMP6_MEMBERSHIP_REDUCTION:
1273 proto_tree_add_text(icmp6_tree, tvb,
1274 offset + offsetof(struct icmp6_hdr, icmp6_maxdelay), 2,
1275 "Maximum response delay: %u",
1276 (guint16)ntohs(dp->icmp6_maxdelay));
1277 proto_tree_add_text(icmp6_tree, tvb, offset + sizeof(*dp), 16,
1278 "Multicast Address: %s",
1279 ip6_to_str((struct e_in6_addr *)(tvb_get_ptr(tvb, offset + sizeof *dp, sizeof (struct e_in6_addr)))));
1281 case ND_ROUTER_SOLICIT:
1282 dissect_icmpv6opt(tvb, offset + sizeof(*dp), pinfo, icmp6_tree);
1284 case ND_ROUTER_ADVERT:
1286 struct nd_router_advert nd_router_advert, *ra;
1290 ra = &nd_router_advert;
1291 tvb_memcpy(tvb, (guint8 *)ra, offset, sizeof *ra);
1292 proto_tree_add_text(icmp6_tree, tvb,
1293 offset + offsetof(struct nd_router_advert, nd_ra_curhoplimit),
1294 1, "Cur hop limit: %u", ra->nd_ra_curhoplimit);
1296 flagoff = offset + offsetof(struct nd_router_advert, nd_ra_flags_reserved);
1297 ra_flags = tvb_get_guint8(tvb, flagoff);
1298 tf = proto_tree_add_text(icmp6_tree, tvb, flagoff, 1, "Flags: 0x%02x", ra_flags);
1299 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1300 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1301 decode_boolean_bitfield(ra_flags,
1302 ND_RA_FLAG_MANAGED, 8, "Managed", "Not managed"));
1303 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1304 decode_boolean_bitfield(ra_flags,
1305 ND_RA_FLAG_OTHER, 8, "Other", "Not other"));
1306 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1307 decode_boolean_bitfield(ra_flags,
1308 ND_RA_FLAG_HOME_AGENT, 8,
1309 "Home Agent", "Not Home Agent"));
1310 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1311 decode_enumerated_bitfield(ra_flags, ND_RA_FLAG_RTPREF_MASK, 8,
1312 names_router_pref, "Router preference: %s"));
1313 proto_tree_add_text(icmp6_tree, tvb,
1314 offset + offsetof(struct nd_router_advert, nd_ra_router_lifetime),
1315 2, "Router lifetime: %u",
1316 (guint16)ntohs(ra->nd_ra_router_lifetime));
1317 proto_tree_add_text(icmp6_tree, tvb,
1318 offset + offsetof(struct nd_router_advert, nd_ra_reachable), 4,
1319 "Reachable time: %u", pntohl(&ra->nd_ra_reachable));
1320 proto_tree_add_text(icmp6_tree, tvb,
1321 offset + offsetof(struct nd_router_advert, nd_ra_retransmit), 4,
1322 "Retrans time: %u", pntohl(&ra->nd_ra_retransmit));
1323 dissect_icmpv6opt(tvb, offset + sizeof(struct nd_router_advert), pinfo, icmp6_tree);
1326 case ND_NEIGHBOR_SOLICIT:
1328 struct nd_neighbor_solicit nd_neighbor_solicit, *ns;
1330 ns = &nd_neighbor_solicit;
1331 tvb_memcpy(tvb, (guint8 *)ns, offset, sizeof *ns);
1332 proto_tree_add_text(icmp6_tree, tvb,
1333 offset + offsetof(struct nd_neighbor_solicit, nd_ns_target), 16,
1336 get_hostname6(&ns->nd_ns_target),
1340 ip6_to_str(&ns->nd_ns_target));
1342 dissect_icmpv6opt(tvb, offset + sizeof(*ns), pinfo, icmp6_tree);
1345 case ND_NEIGHBOR_ADVERT:
1347 int flagoff, targetoff;
1349 struct e_in6_addr na_target;
1351 flagoff = offset + offsetof(struct nd_neighbor_advert, nd_na_flags_reserved);
1352 na_flags = tvb_get_ntohl(tvb, flagoff);
1354 tf = proto_tree_add_text(icmp6_tree, tvb, flagoff, 4, "Flags: 0x%08x", na_flags);
1355 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1356 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
1357 decode_boolean_bitfield(na_flags,
1358 ND_NA_FLAG_ROUTER, 32, "Router", "Not router"));
1359 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
1360 decode_boolean_bitfield(na_flags,
1361 ND_NA_FLAG_SOLICITED, 32, "Solicited", "Not adverted"));
1362 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
1363 decode_boolean_bitfield(na_flags,
1364 ND_NA_FLAG_OVERRIDE, 32, "Override", "Not override"));
1366 targetoff = offset + offsetof(struct nd_neighbor_advert, nd_na_target);
1367 tvb_memcpy(tvb, (guint8 *)&na_target, targetoff, sizeof na_target);
1368 proto_tree_add_text(icmp6_tree, tvb, targetoff, 16,
1371 get_hostname6(&na_target),
1375 ip6_to_str(&na_target));
1377 dissect_icmpv6opt(tvb, offset + sizeof(struct nd_neighbor_advert), pinfo, icmp6_tree);
1382 struct nd_redirect nd_redirect, *rd;
1385 tvb_memcpy(tvb, (guint8 *)rd, offset, sizeof *rd);
1386 proto_tree_add_text(icmp6_tree, tvb,
1387 offset + offsetof(struct nd_redirect, nd_rd_target), 16,
1390 get_hostname6(&rd->nd_rd_target),
1394 ip6_to_str(&rd->nd_rd_target));
1396 proto_tree_add_text(icmp6_tree, tvb,
1397 offset + offsetof(struct nd_redirect, nd_rd_dst), 16,
1399 "Destination: %s (%s)",
1400 get_hostname6(&rd->nd_rd_dst),
1404 ip6_to_str(&rd->nd_rd_dst));
1406 dissect_icmpv6opt(tvb, offset + sizeof(*rd), pinfo, icmp6_tree);
1409 case ICMP6_ROUTER_RENUMBERING:
1410 dissect_rrenum(tvb, offset, pinfo, icmp6_tree);
1412 case ICMP6_NI_QUERY:
1413 case ICMP6_NI_REPLY:
1414 ni = (struct icmp6_nodeinfo *)dp;
1415 proto_tree_add_text(icmp6_tree, tvb,
1416 offset + offsetof(struct icmp6_nodeinfo, ni_qtype),
1417 sizeof(ni->ni_qtype),
1418 "Query type: 0x%04x (%s)", pntohs(&ni->ni_qtype),
1419 val_to_str(pntohs(&ni->ni_qtype), names_nodeinfo_qtype,
1421 dissect_nodeinfo(tvb, offset, pinfo, icmp6_tree);
1424 next_tvb = tvb_new_subset(tvb, offset + sizeof(*dp), -1, -1);
1425 call_dissector(data_handle,next_tvb, pinfo, tree);
1432 proto_register_icmpv6(void)
1434 static hf_register_info hf[] = {
1436 { "Type", "icmpv6.type", FT_UINT8, BASE_DEC, NULL, 0x0,
1439 { "Code", "icmpv6.code", FT_UINT8, BASE_DEC, NULL, 0x0,
1441 { &hf_icmpv6_checksum,
1442 { "Checksum", "icmpv6.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
1444 { &hf_icmpv6_checksum_bad,
1445 { "Bad Checksum", "icmpv6.checksum_bad", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1448 static gint *ett[] = {
1453 &ett_nodeinfo_subject4,
1454 &ett_nodeinfo_subject6,
1455 &ett_nodeinfo_node4,
1456 &ett_nodeinfo_node6,
1457 &ett_nodeinfo_nodebitmap,
1458 &ett_nodeinfo_nodedns,
1461 proto_icmpv6 = proto_register_protocol("Internet Control Message Protocol v6",
1462 "ICMPv6", "icmpv6");
1463 proto_register_field_array(proto_icmpv6, hf, array_length(hf));
1464 proto_register_subtree_array(ett, array_length(ett));
1468 proto_reg_handoff_icmpv6(void)
1470 dissector_handle_t icmpv6_handle;
1472 icmpv6_handle = create_dissector_handle(dissect_icmpv6, proto_icmpv6);
1473 dissector_add("ip.proto", IP_PROTO_ICMPV6, icmpv6_handle);
1476 * Get a handle for the IPv6 dissector.
1478 ipv6_handle = find_dissector("ipv6");
1479 data_handle = find_dissector("data");