2 * Routines for ICMPv6 packet disassembly
4 * $Id: packet-icmpv6.c,v 1.63 2002/01/21 07:36:35 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)
130 address save_net_src;
131 address save_net_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_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), tvb_length_remaining(tvb, offset), "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_length_remaining(tvb, offset + sizeof(*ni));
694 n /= sizeof(guint32);
695 tf = proto_tree_add_text(tree, tvb,
696 offset + sizeof(*ni), tvb_length_remaining(tvb, offset), "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), tvb_length_remaining(tvb, p),
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_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),
754 tvb_length_remaining(tvb, offset),
756 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_nodedns);
757 j = offset + sizeof (*ni) + sizeof(guint32);
758 while (j < tvb_length(tvb)) {
759 l = get_dns_name(tvb, j,
760 offset + sizeof (*ni) + sizeof(guint32),
761 dname,sizeof(dname));
762 if (tvb_bytes_exist(tvb, j + l, 1) &&
763 tvb_get_guint8(tvb, j + l) == 0) {
765 proto_tree_add_text(field_tree, tvb, j, l,
766 "DNS label: %s (truncated)", dname);
768 proto_tree_add_text(field_tree, tvb, j, l,
769 "DNS label: %s", dname);
773 off = tvb_length_remaining(tvb, offset);
775 case NI_QTYPE_NODEADDR:
776 n = tvb_length_remaining(tvb, offset + sizeof(*ni));
777 n /= sizeof(gint32) + sizeof(struct e_in6_addr);
778 tf = proto_tree_add_text(tree, tvb,
779 offset + sizeof(*ni), tvb_length_remaining(tvb, offset), "IPv6 node addresses");
780 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_node6);
781 p = offset + sizeof (*ni);
782 for (i = 0; i < n; i++) {
783 struct e_in6_addr e_in6_addr;
785 ttl = (gint32)tvb_get_ntohl(tvb, p);
786 tvb_memcpy(tvb, (guint8 *)&e_in6_addr, p + sizeof ttl, sizeof e_in6_addr);
787 proto_tree_add_text(field_tree, tvb,
788 p, sizeof(struct e_in6_addr) + sizeof(gint32),
789 "%s (TTL %d)", ip6_to_str(&e_in6_addr), ttl);
790 p += sizeof(struct e_in6_addr) + sizeof(gint32);
792 off = tvb_length_remaining(tvb, offset);
794 case NI_QTYPE_IPV4ADDR:
795 n = tvb_length_remaining(tvb, offset + sizeof(*ni));
796 n /= sizeof(gint32) + sizeof(guint32);
797 tf = proto_tree_add_text(tree, tvb,
798 offset + sizeof(*ni), tvb_length_remaining(tvb, offset), "IPv4 node addresses");
799 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_node4);
800 p = offset + sizeof *ni;
801 for (i = 0; i < n; i++) {
802 tvb_memcpy(tvb, ipaddr, sizeof(gint32) + p, 4);
803 proto_tree_add_text(field_tree, tvb,
804 p, sizeof(guint32), "%s (TTL %d)", ip_to_str(ipaddr), tvb_get_ntohl(tvb, p));
805 p += sizeof(gint32) + sizeof(guint32);
807 off = tvb_length_remaining(tvb, offset);
813 /* the rest of data */
814 call_dissector(data_handle,tvb_new_subset(tvb, offset + off, -1, -1), pinfo, tree);
818 dissect_rrenum(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
820 proto_tree *field_tree, *opt_tree;
822 struct icmp6_router_renum icmp6_router_renum, *rr;
823 struct rr_pco_match rr_pco_match, *match;
824 struct rr_pco_use rr_pco_use, *use;
829 rr = &icmp6_router_renum;
830 tvb_memcpy(tvb, (guint8 *)rr, offset, sizeof *rr);
831 proto_tree_add_text(tree, tvb,
832 offset + offsetof(struct icmp6_router_renum, rr_seqnum), 4,
833 "Sequence number: 0x%08x", pntohl(&rr->rr_seqnum));
834 proto_tree_add_text(tree, tvb,
835 offset + offsetof(struct icmp6_router_renum, rr_segnum), 1,
836 "Segment number: 0x%02x", rr->rr_segnum);
838 flagoff = offset + offsetof(struct icmp6_router_renum, rr_flags);
839 flags = tvb_get_guint8(tvb, flagoff);
840 tf = proto_tree_add_text(tree, tvb, flagoff, 1,
841 "Flags: 0x%02x", flags);
842 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
843 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
844 decode_boolean_bitfield(flags, 0x80, 8,
845 "Test command", "Not test command"));
846 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
847 decode_boolean_bitfield(flags, 0x40, 8,
848 "Result requested", "Result not requested"));
849 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
850 decode_boolean_bitfield(flags, 0x20, 8,
851 "All interfaces", "Not all interfaces"));
852 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
853 decode_boolean_bitfield(flags, 0x10, 8,
854 "Site specific", "Not site specific"));
855 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
856 decode_boolean_bitfield(flags, 0x08, 8,
857 "Processed previously", "Complete result"));
859 proto_tree_add_text(tree, tvb,
860 offset + offsetof(struct icmp6_router_renum, rr_maxdelay), 2,
861 "Max delay: 0x%04x", pntohs(&rr->rr_maxdelay));
862 call_dissector(data_handle,tvb_new_subset(tvb, offset + sizeof(*rr), -1, -1), pinfo, tree); /*XXX*/
864 if (rr->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) {
865 off = offset + sizeof(*rr);
866 match = &rr_pco_match;
867 tvb_memcpy(tvb, (guint8 *)match, off, sizeof *match);
868 tf = proto_tree_add_text(tree, tvb, off, sizeof(*match),
869 "Match-Prefix: %s/%u (%u-%u)", ip6_to_str(&match->rpm_prefix),
870 match->rpm_matchlen, match->rpm_minlen, match->rpm_maxlen);
871 opt_tree = proto_item_add_subtree(tf, ett_icmpv6opt);
872 proto_tree_add_text(opt_tree, tvb,
873 off + offsetof(struct rr_pco_match, rpm_code),
874 sizeof(match->rpm_code), "OpCode: %s (%u)",
875 val_to_str(match->rpm_code, names_rrenum_matchcode, "Unknown"),
877 proto_tree_add_text(opt_tree, tvb,
878 off + offsetof(struct rr_pco_match, rpm_len),
879 sizeof(match->rpm_len), "OpLength: %u (%u octets)",
880 match->rpm_len, match->rpm_len * 8);
881 proto_tree_add_text(opt_tree, tvb,
882 off + offsetof(struct rr_pco_match, rpm_ordinal),
883 sizeof(match->rpm_ordinal), "Ordinal: %u", match->rpm_ordinal);
884 proto_tree_add_text(opt_tree, tvb,
885 off + offsetof(struct rr_pco_match, rpm_matchlen),
886 sizeof(match->rpm_matchlen), "MatchLen: %u", match->rpm_matchlen);
887 proto_tree_add_text(opt_tree, tvb,
888 off + offsetof(struct rr_pco_match, rpm_minlen),
889 sizeof(match->rpm_minlen), "MinLen: %u", match->rpm_minlen);
890 proto_tree_add_text(opt_tree, tvb,
891 off + offsetof(struct rr_pco_match, rpm_maxlen),
892 sizeof(match->rpm_maxlen), "MaxLen: %u", match->rpm_maxlen);
893 proto_tree_add_text(opt_tree, tvb,
894 off + offsetof(struct rr_pco_match, rpm_prefix),
895 sizeof(match->rpm_prefix), "MatchPrefix: %s",
896 ip6_to_str(&match->rpm_prefix));
898 off += sizeof(*match);
900 for (l = match->rpm_len * 8 - sizeof(*match);
901 l >= sizeof(*use); l -= sizeof(*use), off += sizeof(*use)) {
902 tvb_memcpy(tvb, (guint8 *)use, off, sizeof *use);
903 tf = proto_tree_add_text(tree, tvb, off, sizeof(*use),
904 "Use-Prefix: %s/%u (keep %u)", ip6_to_str(&use->rpu_prefix),
905 use->rpu_uselen, use->rpu_keeplen);
906 opt_tree = proto_item_add_subtree(tf, ett_icmpv6opt);
907 proto_tree_add_text(opt_tree, tvb,
908 off + offsetof(struct rr_pco_use, rpu_uselen),
909 sizeof(use->rpu_uselen), "UseLen: %u", use->rpu_uselen);
910 proto_tree_add_text(opt_tree, tvb,
911 off + offsetof(struct rr_pco_use, rpu_keeplen),
912 sizeof(use->rpu_keeplen), "KeepLen: %u", use->rpu_keeplen);
913 tf = proto_tree_add_text(opt_tree, tvb,
914 flagoff = off + offsetof(struct rr_pco_use, rpu_ramask),
915 sizeof(use->rpu_ramask), "FlagMask: 0x%x", use->rpu_ramask);
916 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
917 flags = tvb_get_guint8(tvb, flagoff);
918 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
919 decode_boolean_bitfield(flags,
920 ICMP6_RR_PCOUSE_RAFLAGS_ONLINK, 8,
921 "Onlink", "Not onlink"));
922 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
923 decode_boolean_bitfield(flags,
924 ICMP6_RR_PCOUSE_RAFLAGS_AUTO, 8,
925 "Auto", "Not auto"));
926 tf = proto_tree_add_text(opt_tree, tvb,
927 flagoff = off + offsetof(struct rr_pco_use, rpu_raflags),
928 sizeof(use->rpu_raflags), "RAFlags: 0x%x", use->rpu_raflags);
929 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
930 flags = tvb_get_guint8(tvb, flagoff);
931 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
932 decode_boolean_bitfield(flags,
933 ICMP6_RR_PCOUSE_RAFLAGS_ONLINK, 8,
934 "Onlink", "Not onlink"));
935 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
936 decode_boolean_bitfield(flags,
937 ICMP6_RR_PCOUSE_RAFLAGS_AUTO, 8, "Auto", "Not auto"));
938 if (pntohl(&use->rpu_vltime) == 0xffffffff)
939 proto_tree_add_text(opt_tree, tvb,
940 off + offsetof(struct rr_pco_use, rpu_vltime),
941 sizeof(use->rpu_vltime), "Valid Lifetime: infinity");
943 proto_tree_add_text(opt_tree, tvb,
944 off + offsetof(struct rr_pco_use, rpu_vltime),
945 sizeof(use->rpu_vltime), "Valid Lifetime: %u",
946 pntohl(&use->rpu_vltime));
947 if (pntohl(&use->rpu_pltime) == 0xffffffff)
948 proto_tree_add_text(opt_tree, tvb,
949 off + offsetof(struct rr_pco_use, rpu_pltime),
950 sizeof(use->rpu_pltime), "Preferred Lifetime: infinity");
952 proto_tree_add_text(opt_tree, tvb,
953 off + offsetof(struct rr_pco_use, rpu_pltime),
954 sizeof(use->rpu_pltime), "Preferred Lifetime: %u",
955 pntohl(&use->rpu_pltime));
956 tf = proto_tree_add_text(opt_tree, tvb,
957 flagoff = off + offsetof(struct rr_pco_use, rpu_flags),
958 sizeof(use->rpu_flags), "Flags: 0x%08x",
959 pntohl(&use->rpu_flags));
960 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
961 flags = tvb_get_guint8(tvb, flagoff);
962 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
963 decode_boolean_bitfield(flags,
964 ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, 32,
965 "Decrement valid lifetime", "No decrement valid lifetime"));
966 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
967 decode_boolean_bitfield(flags,
968 ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, 32,
969 "Decrement preferred lifetime",
970 "No decrement preferred lifetime"));
971 proto_tree_add_text(opt_tree, tvb,
972 off + offsetof(struct rr_pco_use, rpu_prefix),
973 sizeof(use->rpu_prefix), "UsePrefix: %s",
974 ip6_to_str(&use->rpu_prefix));
981 dissect_icmpv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
983 proto_tree *icmp6_tree, *field_tree;
984 proto_item *ti, *tf = NULL;
985 struct icmp6_hdr icmp6_hdr, *dp;
986 struct icmp6_nodeinfo *ni = NULL;
987 char *codename, *typename;
988 char *colcodename, *coltypename;
990 guint length, reported_length;
993 guint16 cksum, computed_cksum;
997 if (check_col(pinfo->cinfo, COL_PROTOCOL))
998 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ICMPv6");
999 if (check_col(pinfo->cinfo, COL_INFO))
1000 col_clear(pinfo->cinfo, COL_INFO);
1003 tvb_memcpy(tvb, (guint8 *)&icmp6_hdr, offset, sizeof icmp6_hdr);
1005 codename = typename = colcodename = coltypename = "Unknown";
1007 switch (dp->icmp6_type) {
1008 case ICMP6_DST_UNREACH:
1009 typename = coltypename = "Unreachable";
1010 switch (dp->icmp6_code) {
1011 case ICMP6_DST_UNREACH_NOROUTE:
1012 codename = colcodename = "Route unreachable";
1014 case ICMP6_DST_UNREACH_ADMIN:
1015 codename = colcodename = "Administratively prohibited";
1017 case ICMP6_DST_UNREACH_NOTNEIGHBOR:
1018 codename = colcodename = "Not a neighbor";
1020 case ICMP6_DST_UNREACH_ADDR:
1021 codename = colcodename = "Address unreachable";
1023 case ICMP6_DST_UNREACH_NOPORT:
1024 codename = colcodename = "Port unreachable";
1028 case ICMP6_PACKET_TOO_BIG:
1029 typename = coltypename = "Too big";
1030 codename = colcodename = NULL;
1032 case ICMP6_TIME_EXCEEDED:
1033 typename = coltypename = "Time exceeded";
1034 switch (dp->icmp6_code) {
1035 case ICMP6_TIME_EXCEED_TRANSIT:
1036 codename = colcodename = "In-transit";
1038 case ICMP6_TIME_EXCEED_REASSEMBLY:
1039 codename = colcodename = "Reassembly";
1043 case ICMP6_PARAM_PROB:
1044 typename = coltypename = "Parameter problem";
1045 switch (dp->icmp6_code) {
1046 case ICMP6_PARAMPROB_HEADER:
1047 codename = colcodename = "Header";
1049 case ICMP6_PARAMPROB_NEXTHEADER:
1050 codename = colcodename = "Next header";
1052 case ICMP6_PARAMPROB_OPTION:
1053 codename = colcodename = "Option";
1057 case ICMP6_ECHO_REQUEST:
1058 typename = coltypename = "Echo request";
1059 codename = colcodename = NULL;
1061 case ICMP6_ECHO_REPLY:
1062 typename = coltypename = "Echo reply";
1063 codename = colcodename = NULL;
1065 case ICMP6_MEMBERSHIP_QUERY:
1066 typename = coltypename = "Multicast listener query";
1067 codename = colcodename = NULL;
1069 case ICMP6_MEMBERSHIP_REPORT:
1070 typename = coltypename = "Multicast listener report";
1071 codename = colcodename = NULL;
1073 case ICMP6_MEMBERSHIP_REDUCTION:
1074 typename = coltypename = "Multicast listener done";
1075 codename = colcodename = NULL;
1077 case ND_ROUTER_SOLICIT:
1078 typename = coltypename = "Router solicitation";
1079 codename = colcodename = NULL;
1080 len = sizeof(struct nd_router_solicit);
1082 case ND_ROUTER_ADVERT:
1083 typename = coltypename = "Router advertisement";
1084 codename = colcodename = NULL;
1085 len = sizeof(struct nd_router_advert);
1087 case ND_NEIGHBOR_SOLICIT:
1088 typename = coltypename = "Neighbor solicitation";
1089 codename = colcodename = NULL;
1090 len = sizeof(struct nd_neighbor_solicit);
1092 case ND_NEIGHBOR_ADVERT:
1093 typename = coltypename = "Neighbor advertisement";
1094 codename = colcodename = NULL;
1095 len = sizeof(struct nd_neighbor_advert);
1098 typename = coltypename = "Redirect";
1099 codename = colcodename = NULL;
1100 len = sizeof(struct nd_redirect);
1102 case ICMP6_ROUTER_RENUMBERING:
1103 typename = coltypename = "Router renumbering";
1104 switch (dp->icmp6_code) {
1105 case ICMP6_ROUTER_RENUMBERING_COMMAND:
1106 codename = colcodename = "Command";
1108 case ICMP6_ROUTER_RENUMBERING_RESULT:
1109 codename = colcodename = "Result";
1111 case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
1112 codename = colcodename = "Sequence number reset";
1115 len = sizeof(struct icmp6_router_renum);
1117 case ICMP6_NI_QUERY:
1118 case ICMP6_NI_REPLY:
1119 ni = (struct icmp6_nodeinfo *)dp;
1120 if (ni->ni_type == ICMP6_NI_QUERY) {
1121 typename = coltypename = "Node information query";
1122 switch (ni->ni_code) {
1123 case ICMP6_NI_SUBJ_IPV6:
1124 codename = "Query subject = IPv6 addresses";
1126 case ICMP6_NI_SUBJ_FQDN:
1127 if (tvb_bytes_exist(tvb, offset, sizeof(*ni)))
1128 codename = "Query subject = DNS name";
1130 codename = "Query subject = empty";
1132 case ICMP6_NI_SUBJ_IPV4:
1133 codename = "Query subject = IPv4 addresses";
1137 typename = coltypename = "Node information reply";
1138 switch (ni->ni_code) {
1139 case ICMP6_NI_SUCCESS:
1140 codename = "Successful";
1142 case ICMP6_NI_REFUSED:
1143 codename = "Refused";
1145 case ICMP6_NI_UNKNOWN:
1146 codename = "Unknown query type";
1150 colcodename = val_to_str(pntohs(&ni->ni_qtype), names_nodeinfo_qtype,
1152 len = sizeof(struct icmp6_nodeinfo);
1156 if (check_col(pinfo->cinfo, COL_INFO)) {
1157 char typebuf[256], codebuf[256];
1159 if (coltypename && strcmp(coltypename, "Unknown") == 0) {
1160 snprintf(typebuf, sizeof(typebuf), "Unknown (0x%02x)",
1162 coltypename = typebuf;
1164 if (colcodename && strcmp(colcodename, "Unknown") == 0) {
1165 snprintf(codebuf, sizeof(codebuf), "Unknown (0x%02x)",
1167 colcodename = codebuf;
1170 col_add_fstr(pinfo->cinfo, COL_INFO, "%s (%s)", coltypename, colcodename);
1172 col_add_fstr(pinfo->cinfo, COL_INFO, "%s", coltypename);
1177 /* !!! specify length */
1178 ti = proto_tree_add_item(tree, proto_icmpv6, tvb, offset, len, FALSE);
1179 icmp6_tree = proto_item_add_subtree(ti, ett_icmpv6);
1181 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_type, tvb,
1182 offset + offsetof(struct icmp6_hdr, icmp6_type), 1,
1184 "Type: %u (%s)", dp->icmp6_type, typename);
1186 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_code, tvb,
1187 offset + offsetof(struct icmp6_hdr, icmp6_code), 1,
1189 "Code: %u (%s)", dp->icmp6_code, codename);
1191 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_code, tvb,
1192 offset + offsetof(struct icmp6_hdr, icmp6_code), 1,
1194 "Code: %u", dp->icmp6_code);
1196 cksum = (guint16)htons(dp->icmp6_cksum);
1197 length = tvb_length(tvb);
1198 reported_length = tvb_reported_length(tvb);
1199 if (!pinfo->fragmented && length >= reported_length) {
1200 /* The packet isn't part of a fragmented datagram and isn't
1201 truncated, so we can checksum it. */
1203 /* Set up the fields of the pseudo-header. */
1204 cksum_vec[0].ptr = pinfo->src.data;
1205 cksum_vec[0].len = pinfo->src.len;
1206 cksum_vec[1].ptr = pinfo->dst.data;
1207 cksum_vec[1].len = pinfo->dst.len;
1208 cksum_vec[2].ptr = (const guint8 *)&phdr;
1209 phdr[0] = htonl(tvb_reported_length(tvb));
1210 phdr[1] = htonl(IP_PROTO_ICMPV6);
1211 cksum_vec[2].len = 8;
1212 cksum_vec[3].len = tvb_reported_length(tvb);
1213 cksum_vec[3].ptr = tvb_get_ptr(tvb, offset, cksum_vec[3].len);
1214 computed_cksum = in_cksum(cksum_vec, 4);
1215 if (computed_cksum == 0) {
1216 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_checksum,
1218 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1220 "Checksum: 0x%04x (correct)", cksum);
1222 proto_tree_add_boolean_hidden(icmp6_tree, hf_icmpv6_checksum_bad,
1224 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1226 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_checksum,
1228 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1230 "Checksum: 0x%04x (incorrect, should be 0x%04x)",
1231 cksum, in_cksum_shouldbe(cksum, computed_cksum));
1234 proto_tree_add_uint(icmp6_tree, hf_icmpv6_checksum, tvb,
1235 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1240 switch (dp->icmp6_type) {
1241 case ICMP6_DST_UNREACH:
1242 case ICMP6_TIME_EXCEEDED:
1243 dissect_contained_icmpv6(tvb, offset + sizeof(*dp), pinfo,
1246 case ICMP6_PACKET_TOO_BIG:
1247 proto_tree_add_text(icmp6_tree, tvb,
1248 offset + offsetof(struct icmp6_hdr, icmp6_mtu), 4,
1249 "MTU: %u", pntohl(&dp->icmp6_mtu));
1250 dissect_contained_icmpv6(tvb, offset + sizeof(*dp), pinfo,
1253 case ICMP6_PARAM_PROB:
1254 proto_tree_add_text(icmp6_tree, tvb,
1255 offset + offsetof(struct icmp6_hdr, icmp6_pptr), 4,
1256 "Problem pointer: 0x%04x", pntohl(&dp->icmp6_pptr));
1257 dissect_contained_icmpv6(tvb, offset + sizeof(*dp), pinfo,
1260 case ICMP6_ECHO_REQUEST:
1261 case ICMP6_ECHO_REPLY:
1262 proto_tree_add_text(icmp6_tree, tvb,
1263 offset + offsetof(struct icmp6_hdr, icmp6_id), 2,
1264 "ID: 0x%04x", (guint16)ntohs(dp->icmp6_id));
1265 proto_tree_add_text(icmp6_tree, tvb,
1266 offset + offsetof(struct icmp6_hdr, icmp6_seq), 2,
1267 "Sequence: 0x%04x", (guint16)ntohs(dp->icmp6_seq));
1268 next_tvb = tvb_new_subset(tvb, offset + sizeof(*dp), -1, -1);
1269 call_dissector(data_handle,next_tvb, pinfo, icmp6_tree);
1271 case ICMP6_MEMBERSHIP_QUERY:
1272 case ICMP6_MEMBERSHIP_REPORT:
1273 case ICMP6_MEMBERSHIP_REDUCTION:
1274 proto_tree_add_text(icmp6_tree, tvb,
1275 offset + offsetof(struct icmp6_hdr, icmp6_maxdelay), 2,
1276 "Maximum response delay: %u",
1277 (guint16)ntohs(dp->icmp6_maxdelay));
1278 proto_tree_add_text(icmp6_tree, tvb, offset + sizeof(*dp), 16,
1279 "Multicast Address: %s",
1280 ip6_to_str((struct e_in6_addr *)(tvb_get_ptr(tvb, offset + sizeof *dp, sizeof (struct e_in6_addr)))));
1282 case ND_ROUTER_SOLICIT:
1283 dissect_icmpv6opt(tvb, offset + sizeof(*dp), pinfo, icmp6_tree);
1285 case ND_ROUTER_ADVERT:
1287 struct nd_router_advert nd_router_advert, *ra;
1291 ra = &nd_router_advert;
1292 tvb_memcpy(tvb, (guint8 *)ra, offset, sizeof *ra);
1293 proto_tree_add_text(icmp6_tree, tvb,
1294 offset + offsetof(struct nd_router_advert, nd_ra_curhoplimit),
1295 1, "Cur hop limit: %u", ra->nd_ra_curhoplimit);
1297 flagoff = offset + offsetof(struct nd_router_advert, nd_ra_flags_reserved);
1298 ra_flags = tvb_get_guint8(tvb, flagoff);
1299 tf = proto_tree_add_text(icmp6_tree, tvb, flagoff, 1, "Flags: 0x%02x", ra_flags);
1300 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1301 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1302 decode_boolean_bitfield(ra_flags,
1303 ND_RA_FLAG_MANAGED, 8, "Managed", "Not managed"));
1304 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1305 decode_boolean_bitfield(ra_flags,
1306 ND_RA_FLAG_OTHER, 8, "Other", "Not other"));
1307 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1308 decode_boolean_bitfield(ra_flags,
1309 ND_RA_FLAG_HOME_AGENT, 8,
1310 "Home Agent", "Not Home Agent"));
1311 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1312 decode_enumerated_bitfield(ra_flags, ND_RA_FLAG_RTPREF_MASK, 8,
1313 names_router_pref, "Router preference: %s"));
1314 proto_tree_add_text(icmp6_tree, tvb,
1315 offset + offsetof(struct nd_router_advert, nd_ra_router_lifetime),
1316 2, "Router lifetime: %u",
1317 (guint16)ntohs(ra->nd_ra_router_lifetime));
1318 proto_tree_add_text(icmp6_tree, tvb,
1319 offset + offsetof(struct nd_router_advert, nd_ra_reachable), 4,
1320 "Reachable time: %u", pntohl(&ra->nd_ra_reachable));
1321 proto_tree_add_text(icmp6_tree, tvb,
1322 offset + offsetof(struct nd_router_advert, nd_ra_retransmit), 4,
1323 "Retrans time: %u", pntohl(&ra->nd_ra_retransmit));
1324 dissect_icmpv6opt(tvb, offset + sizeof(struct nd_router_advert), pinfo, icmp6_tree);
1327 case ND_NEIGHBOR_SOLICIT:
1329 struct nd_neighbor_solicit nd_neighbor_solicit, *ns;
1331 ns = &nd_neighbor_solicit;
1332 tvb_memcpy(tvb, (guint8 *)ns, offset, sizeof *ns);
1333 proto_tree_add_text(icmp6_tree, tvb,
1334 offset + offsetof(struct nd_neighbor_solicit, nd_ns_target), 16,
1337 get_hostname6(&ns->nd_ns_target),
1341 ip6_to_str(&ns->nd_ns_target));
1343 dissect_icmpv6opt(tvb, offset + sizeof(*ns), pinfo, icmp6_tree);
1346 case ND_NEIGHBOR_ADVERT:
1348 int flagoff, targetoff;
1350 struct e_in6_addr na_target;
1352 flagoff = offset + offsetof(struct nd_neighbor_advert, nd_na_flags_reserved);
1353 na_flags = tvb_get_ntohl(tvb, flagoff);
1355 tf = proto_tree_add_text(icmp6_tree, tvb, flagoff, 4, "Flags: 0x%08x", na_flags);
1356 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1357 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
1358 decode_boolean_bitfield(na_flags,
1359 ND_NA_FLAG_ROUTER, 32, "Router", "Not router"));
1360 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
1361 decode_boolean_bitfield(na_flags,
1362 ND_NA_FLAG_SOLICITED, 32, "Solicited", "Not adverted"));
1363 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
1364 decode_boolean_bitfield(na_flags,
1365 ND_NA_FLAG_OVERRIDE, 32, "Override", "Not override"));
1367 targetoff = offset + offsetof(struct nd_neighbor_advert, nd_na_target);
1368 tvb_memcpy(tvb, (guint8 *)&na_target, targetoff, sizeof na_target);
1369 proto_tree_add_text(icmp6_tree, tvb, targetoff, 16,
1372 get_hostname6(&na_target),
1376 ip6_to_str(&na_target));
1378 dissect_icmpv6opt(tvb, offset + sizeof(struct nd_neighbor_advert), pinfo, icmp6_tree);
1383 struct nd_redirect nd_redirect, *rd;
1386 tvb_memcpy(tvb, (guint8 *)rd, offset, sizeof *rd);
1387 proto_tree_add_text(icmp6_tree, tvb,
1388 offset + offsetof(struct nd_redirect, nd_rd_target), 16,
1391 get_hostname6(&rd->nd_rd_target),
1395 ip6_to_str(&rd->nd_rd_target));
1397 proto_tree_add_text(icmp6_tree, tvb,
1398 offset + offsetof(struct nd_redirect, nd_rd_dst), 16,
1400 "Destination: %s (%s)",
1401 get_hostname6(&rd->nd_rd_dst),
1405 ip6_to_str(&rd->nd_rd_dst));
1407 dissect_icmpv6opt(tvb, offset + sizeof(*rd), pinfo, icmp6_tree);
1410 case ICMP6_ROUTER_RENUMBERING:
1411 dissect_rrenum(tvb, offset, pinfo, icmp6_tree);
1413 case ICMP6_NI_QUERY:
1414 case ICMP6_NI_REPLY:
1415 ni = (struct icmp6_nodeinfo *)dp;
1416 proto_tree_add_text(icmp6_tree, tvb,
1417 offset + offsetof(struct icmp6_nodeinfo, ni_qtype),
1418 sizeof(ni->ni_qtype),
1419 "Query type: 0x%04x (%s)", pntohs(&ni->ni_qtype),
1420 val_to_str(pntohs(&ni->ni_qtype), names_nodeinfo_qtype,
1422 dissect_nodeinfo(tvb, offset, pinfo, icmp6_tree);
1425 next_tvb = tvb_new_subset(tvb, offset + sizeof(*dp), -1, -1);
1426 call_dissector(data_handle,next_tvb, pinfo, tree);
1433 proto_register_icmpv6(void)
1435 static hf_register_info hf[] = {
1437 { "Type", "icmpv6.type", FT_UINT8, BASE_DEC, NULL, 0x0,
1440 { "Code", "icmpv6.code", FT_UINT8, BASE_DEC, NULL, 0x0,
1442 { &hf_icmpv6_checksum,
1443 { "Checksum", "icmpv6.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
1445 { &hf_icmpv6_checksum_bad,
1446 { "Bad Checksum", "icmpv6.checksum_bad", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1449 static gint *ett[] = {
1454 &ett_nodeinfo_subject4,
1455 &ett_nodeinfo_subject6,
1456 &ett_nodeinfo_node4,
1457 &ett_nodeinfo_node6,
1458 &ett_nodeinfo_nodebitmap,
1459 &ett_nodeinfo_nodedns,
1462 proto_icmpv6 = proto_register_protocol("Internet Control Message Protocol v6",
1463 "ICMPv6", "icmpv6");
1464 proto_register_field_array(proto_icmpv6, hf, array_length(hf));
1465 proto_register_subtree_array(ett, array_length(ett));
1469 proto_reg_handoff_icmpv6(void)
1471 dissector_handle_t icmpv6_handle;
1473 icmpv6_handle = create_dissector_handle(dissect_icmpv6, proto_icmpv6);
1474 dissector_add("ip.proto", IP_PROTO_ICMPV6, icmpv6_handle);
1477 * Get a handle for the IPv6 dissector.
1479 ipv6_handle = find_dissector("ipv6");
1480 data_handle = find_dissector("data");