2 * Routines for ICMPv6 packet disassembly
4 * $Id: packet-icmpv6.c,v 1.42 2001/04/27 01:27:37 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 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
40 #ifdef HAVE_SYS_TYPES_H
41 # include <sys/types.h>
44 #ifdef HAVE_NETINET_IN_H
45 # include <netinet/in.h>
50 #ifdef NEED_SNPRINTF_H
51 # include "snprintf.h"
55 #include "packet-ipv6.h"
56 #include "packet-dns.h"
62 #define offsetof(type, member) ((size_t)(&((type *)0)->member))
65 static int proto_icmpv6 = -1;
66 static int hf_icmpv6_type = -1;
67 static int hf_icmpv6_code = -1;
68 static int hf_icmpv6_checksum = -1;
69 static int hf_icmpv6_checksum_bad = -1;
71 static gint ett_icmpv6 = -1;
72 static gint ett_icmpv6opt = -1;
73 static gint ett_icmpv6flag = -1;
74 static gint ett_nodeinfo_flag = -1;
75 static gint ett_nodeinfo_subject4 = -1;
76 static gint ett_nodeinfo_subject6 = -1;
77 static gint ett_nodeinfo_node4 = -1;
78 static gint ett_nodeinfo_node6 = -1;
79 static gint ett_nodeinfo_nodebitmap = -1;
80 static gint ett_nodeinfo_nodedns = -1;
82 static dissector_handle_t ipv6_handle;
84 static const value_string names_nodeinfo_qtype[] = {
85 { NI_QTYPE_NOOP, "NOOP" },
86 { NI_QTYPE_SUPTYPES, "Supported query types" },
87 { NI_QTYPE_DNSNAME, "DNS name" },
88 { NI_QTYPE_NODEADDR, "Node addresses" },
89 { NI_QTYPE_IPV4ADDR, "IPv4 node addresses" },
93 static const value_string names_rrenum_matchcode[] = {
94 { RPM_PCO_ADD, "Add" },
95 { RPM_PCO_CHANGE, "Change" },
96 { RPM_PCO_SETGLOBAL, "Set Global" },
101 dissect_icmpv6opt(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
103 proto_tree *icmp6opt_tree, *field_tree;
105 struct nd_opt_hdr nd_opt_hdr, *opt;
113 if ((int)tvb_reported_length(tvb) <= offset)
114 return; /* No more options left */
117 tvb_memcpy(tvb, (guint8 *)opt, offset, sizeof *opt);
118 len = opt->nd_opt_len << 3;
120 /* !!! specify length */
121 ti = proto_tree_add_text(tree, tvb, offset, len, "ICMPv6 options");
122 icmp6opt_tree = proto_item_add_subtree(ti, ett_icmpv6opt);
124 switch (opt->nd_opt_type) {
125 case ND_OPT_SOURCE_LINKADDR:
126 typename = "Source link-layer address";
128 case ND_OPT_TARGET_LINKADDR:
129 typename = "Target link-layer address";
131 case ND_OPT_PREFIX_INFORMATION:
132 typename = "Prefix information";
134 case ND_OPT_REDIRECTED_HEADER:
135 typename = "Redirected header";
140 case ND_OPT_ADVERTISEMENT_INTERVAL:
141 typename = "Advertisement Interval";
143 case ND_OPT_HOME_AGENT_INFORMATION:
144 typename = "Home Agent Information";
148 typename = "Unknown";
152 proto_tree_add_text(icmp6opt_tree, tvb,
153 offset + offsetof(struct nd_opt_hdr, nd_opt_type), 1,
154 "Type: %u (%s)", opt->nd_opt_type, typename);
155 proto_tree_add_text(icmp6opt_tree, tvb,
156 offset + offsetof(struct nd_opt_hdr, nd_opt_len), 1,
157 "Length: %u bytes (%u)", opt->nd_opt_len << 3, opt->nd_opt_len);
160 switch (opt->nd_opt_type) {
161 case ND_OPT_SOURCE_LINKADDR:
162 case ND_OPT_TARGET_LINKADDR:
166 len = (opt->nd_opt_len << 3) - sizeof(*opt);
167 t = (char *)malloc(len * 3);
168 memset(t, 0, len * 3);
169 p = offset + sizeof(*opt);
170 for (i = 0; i < len; i++) {
173 sprintf(&t[i * 3], "%02x", tvb_get_guint8(tvb, p + i) & 0xff);
175 proto_tree_add_text(icmp6opt_tree, tvb,
176 offset + sizeof(*opt), len, "Link-layer address: %s", t);
179 case ND_OPT_PREFIX_INFORMATION:
181 struct nd_opt_prefix_info nd_opt_prefix_info, *pi;
184 pi = &nd_opt_prefix_info;
185 tvb_memcpy(tvb, (guint8 *)pi, offset, sizeof *pi);
186 proto_tree_add_text(icmp6opt_tree, tvb,
187 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_prefix_len),
188 1, "Prefix length: %u", pi->nd_opt_pi_prefix_len);
190 flagoff = offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_flags_reserved);
191 tf = proto_tree_add_text(icmp6opt_tree, tvb, flagoff, 1, "Flags: 0x%02x",
192 tvb_get_guint8(tvb, offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_flags_reserved)));
193 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
194 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
195 decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
196 0x80, 8, "Onlink", "Not onlink"));
197 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
198 decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
199 0x40, 8, "Auto", "Not auto"));
200 /* BT INSERT BEGIN */
201 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
202 decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
203 0x20, 8, "Router Address", "Not router address"));
205 proto_tree_add_text(icmp6opt_tree, tvb,
206 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_valid_time),
207 4, "Valid lifetime: 0x%08x",
208 pntohl(&pi->nd_opt_pi_valid_time));
209 proto_tree_add_text(icmp6opt_tree, tvb,
210 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_preferred_time),
211 4, "Preferred lifetime: 0x%08x",
212 pntohl(&pi->nd_opt_pi_preferred_time));
213 proto_tree_add_text(icmp6opt_tree, tvb,
214 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_prefix),
215 16, "Prefix: %s", ip6_to_str(&pi->nd_opt_pi_prefix));
218 case ND_OPT_REDIRECTED_HEADER:
219 proto_tree_add_text(icmp6opt_tree, tvb,
220 offset + 8, (opt->nd_opt_len << 3) - 8, "Redirected packet");
221 /* tiny sanity check */
222 if ((tvb_get_guint8(tvb, offset + 8) & 0xf0) == 0x60) {
223 /* The redirected packet is an IPv6 datagram; dissect it.
225 Set the columns non-writable, so that the packet list
226 shows this as an ICMPv6 packet, not as the type of packet
227 for which the ICMPv6 packet was generated. */
228 col_set_writable(pinfo->fd, FALSE);
230 call_dissector(ipv6_handle, tvb_new_subset(tvb, offset + 8, -1, -1),
231 pinfo, icmp6opt_tree);
233 dissect_data(tvb_new_subset(tvb, offset + 8, -1, -1), 0, pinfo, icmp6opt_tree);
236 proto_tree_add_text(icmp6opt_tree, tvb,
237 offset + offsetof(struct nd_opt_mtu, nd_opt_mtu_mtu), 4,
238 "MTU: %u", tvb_get_ntohl(tvb, offset + offsetof(struct nd_opt_mtu, nd_opt_mtu_mtu)));
240 /* BT INSERT BEGIN */
241 case ND_OPT_ADVERTISEMENT_INTERVAL:
242 proto_tree_add_text(icmp6opt_tree, tvb,
243 offset + offsetof(struct nd_opt_adv_int, nd_opt_adv_int_advint), 4,
244 "Advertisement Interval: %d",
245 tvb_get_ntohl(tvb, offset + offsetof(struct nd_opt_adv_int, nd_opt_adv_int_advint)));
247 case ND_OPT_HOME_AGENT_INFORMATION:
249 struct nd_opt_ha_info *pi = (struct nd_opt_ha_info *)opt;
250 proto_tree_add_text(icmp6opt_tree, tvb,
251 offset + offsetof(struct nd_opt_ha_info, nd_opt_ha_info_ha_pref),
252 2, "Home Agent Preference: %d",
253 pntohs(&pi->nd_opt_ha_info_ha_pref));
254 proto_tree_add_text(icmp6opt_tree, tvb,
255 offset + offsetof(struct nd_opt_ha_info, nd_opt_ha_info_ha_life),
256 2, "Home Agent Lifetime: %d",
257 pntohs(&pi->nd_opt_ha_info_ha_life));
263 if (opt->nd_opt_len == 0) {
264 proto_tree_add_text(icmp6opt_tree, tvb,
265 offset + offsetof(struct nd_opt_hdr, nd_opt_len), 1,
266 "Invalid option length: %u",
271 offset += (opt->nd_opt_len << 3);
276 * draft-ietf-ipngwg-icmp-name-lookups-07.txt
277 * Note that the packet format was changed several times in the past.
281 bitrange0(v, s, buf, buflen)
301 ep = buf + buflen - 1;
302 memset(buf, 0, buflen);
305 /* shift till we have 0x01 */
306 if ((v & 0x01) == 0) {
309 v >>= 4; off += 4; continue;
311 v >>= 3; off += 3; continue;
312 case 0x04: case 0x0c:
313 v >>= 2; off += 2; continue;
315 v >>= 1; off += 1; continue;
319 /* we have 0x01 with us */
320 for (i = 0; i < 32 - off; i++) {
321 if ((v & (0x01 << i)) == 0)
325 l = snprintf(p, ep - p, ",%d", s + off);
327 l = snprintf(p, ep - p, ",%d-%d", s + off,
341 bitrange(tvbuff_t *tvb, int offset, int l, int s)
343 static char buf[1024];
347 memset(buf, 0, sizeof(buf));
349 eq = buf + sizeof(buf) - 1;
350 for (i = 0; i < l; i++) {
351 if (bitrange0(tvb_get_ntohl(tvb, offset + i * 4), s + i * 4, q, eq - q) == NULL) {
352 if (q != buf && q + 5 < buf + sizeof(buf))
353 strncpy(q, ",...", 5);
362 dissect_nodeinfo(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
364 proto_tree *field_tree;
366 struct icmp6_nodeinfo icmp6_nodeinfo, *ni;
371 char dname[MAXDNAME];
374 int top_level_offset;
376 ni = &icmp6_nodeinfo;
377 tvb_memcpy(tvb, (guint8 *)ni, offset, sizeof *ni);
379 flags = pntohs(&ni->ni_flags);
380 tf = proto_tree_add_text(tree, tvb,
381 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
382 sizeof(ni->ni_flags), "Flags: 0x%04x", flags);
383 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_flag);
384 switch (pntohs(&ni->ni_qtype)) {
385 case NI_QTYPE_SUPTYPES:
386 if (ni->ni_type == ICMP6_NI_QUERY) {
387 proto_tree_add_text(field_tree, tvb,
388 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
389 sizeof(ni->ni_flags), "%s",
390 decode_boolean_bitfield(flags, NI_SUPTYPE_FLAG_COMPRESS, sizeof(flags) * 8,
391 "Compressed reply supported",
392 "No compressed reply support"));
394 proto_tree_add_text(field_tree, tvb,
395 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
396 sizeof(ni->ni_flags), "%s",
397 decode_boolean_bitfield(flags, NI_SUPTYPE_FLAG_COMPRESS, sizeof(flags) * 8,
398 "Compressed", "Not compressed"));
401 case NI_QTYPE_DNSNAME:
402 if (ni->ni_type == ICMP6_NI_REPLY) {
403 proto_tree_add_text(field_tree, tvb,
404 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
405 sizeof(ni->ni_flags), "%s",
406 decode_boolean_bitfield(flags, NI_FQDN_FLAG_VALIDTTL, sizeof(flags) * 8,
407 "Valid TTL field", "Meaningless TTL field"));
410 case NI_QTYPE_NODEADDR:
411 proto_tree_add_text(field_tree, tvb,
412 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
413 sizeof(ni->ni_flags), "%s",
414 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_GLOBAL, sizeof(flags) * 8,
416 "Not global address"));
417 proto_tree_add_text(field_tree, tvb,
418 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
419 sizeof(ni->ni_flags), "%s",
420 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_SITELOCAL, sizeof(flags) * 8,
421 "Site-local address",
422 "Not site-local address"));
423 proto_tree_add_text(field_tree, tvb,
424 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
425 sizeof(ni->ni_flags), "%s",
426 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_LINKLOCAL, sizeof(flags) * 8,
427 "Link-local address",
428 "Not link-local address"));
429 proto_tree_add_text(field_tree, tvb,
430 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
431 sizeof(ni->ni_flags), "%s",
432 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_COMPAT, sizeof(flags) * 8,
433 "IPv4 compatible/mapped address",
434 "Not IPv4 compatible/mapped address"));
436 case NI_QTYPE_IPV4ADDR:
437 proto_tree_add_text(field_tree, tvb,
438 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
439 sizeof(ni->ni_flags), "%s",
440 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_ALL, sizeof(flags) * 8,
441 "All unicast address",
442 "Unicast addresses on the queried interface"));
443 proto_tree_add_text(field_tree, tvb,
444 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
445 sizeof(ni->ni_flags), "%s",
446 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_TRUNCATE, sizeof(flags) * 8,
447 "Truncated", "Not truncated"));
452 proto_tree_add_text(tree, tvb,
453 offset + offsetof(struct icmp6_nodeinfo, icmp6_ni_nonce[0]),
454 sizeof(ni->icmp6_ni_nonce), "Nonce: 0x%08x%08x",
455 pntohl(&ni->icmp6_ni_nonce[0]), pntohl(&ni->icmp6_ni_nonce[4]));
457 /* offset for "the rest of data" */
461 if (!tvb_bytes_exist(tvb, offset, sizeof(*ni)))
463 if (ni->ni_type == ICMP6_NI_QUERY) {
464 switch (ni->ni_code) {
465 case ICMP6_NI_SUBJ_IPV6:
466 n = tvb_length_remaining(tvb, offset + sizeof(*ni));
467 n /= sizeof(struct e_in6_addr);
468 tf = proto_tree_add_text(tree, tvb,
469 offset + sizeof(*ni), tvb_length_remaining(tvb, offset), "IPv6 subject addresses");
470 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_subject6);
471 p = offset + sizeof *ni;
472 for (i = 0; i < n; i++) {
473 struct e_in6_addr e_in6_addr;
474 tvb_memcpy(tvb, (guint8 *)&e_in6_addr, p, sizeof e_in6_addr);
475 proto_tree_add_text(field_tree, tvb,
476 p, sizeof(struct e_in6_addr),
477 "%s", ip6_to_str(&e_in6_addr));
478 p += sizeof(struct e_in6_addr);
480 off = tvb_length_remaining(tvb, offset);
482 case ICMP6_NI_SUBJ_FQDN:
483 /* XXXX - clean this up when packet-dns.c has been tvbuffified */
484 tvb_compat(tvb, &pd, &top_level_offset);
485 l = get_dns_name(pd, top_level_offset + offset + sizeof(*ni),
486 top_level_offset + offset + sizeof(*ni),
487 dname, sizeof(dname));
488 if (tvb_bytes_exist(tvb, offset + sizeof(*ni) + l, 1) &&
489 tvb_get_guint8(tvb, offset + sizeof(*ni) + l) == 0) {
491 proto_tree_add_text(tree, tvb, offset + sizeof(*ni), l,
492 "DNS label: %s (truncated)", dname);
494 proto_tree_add_text(tree, tvb, offset + sizeof(*ni), l,
495 "DNS label: %s", dname);
497 off = tvb_length_remaining(tvb, offset + sizeof(*ni) + l);
499 case ICMP6_NI_SUBJ_IPV4:
500 n = tvb_length_remaining(tvb, offset + sizeof(*ni));
501 n /= sizeof(guint32);
502 tf = proto_tree_add_text(tree, tvb,
503 offset + sizeof(*ni), tvb_length_remaining(tvb, offset), "IPv4 subject addresses");
504 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_subject4);
505 p = offset + sizeof *ni;
506 for (i = 0; i < n; i++) {
507 tvb_memcpy(tvb, ipaddr, p, 4);
508 proto_tree_add_text(field_tree, tvb,
509 p, sizeof(guint32), "%s", ip_to_str(ipaddr));
510 p += sizeof(guint32);
512 off = tvb_length_remaining(tvb, offset);
516 switch (pntohs(&ni->ni_qtype)) {
519 case NI_QTYPE_SUPTYPES:
520 p = offset + sizeof *ni;
521 tf = proto_tree_add_text(tree, tvb,
522 offset + sizeof(*ni), tvb_length_remaining(tvb, p),
523 "Supported type bitmap%s",
524 (flags & 0x0001) ? ", compressed" : "");
525 field_tree = proto_item_add_subtree(tf,
526 ett_nodeinfo_nodebitmap);
528 while (tvb_bytes_exist(tvb, p, sizeof(guint32))) { /* XXXX Check what? */
529 if ((flags & 0x0001) == 0) {
530 l = tvb_length_remaining(tvb, offset + sizeof(*ni));
531 l /= sizeof(guint32);
534 l = tvb_get_ntohs(tvb, p);
535 i = tvb_get_ntohs(tvb, p + sizeof(guint16)); /*skip*/
537 if (n + l * 32 > (1 << 16))
539 if (n + (l + i) * 32 > (1 << 16))
541 if ((flags & 0x0001) == 0) {
542 proto_tree_add_text(field_tree, tvb, p,
543 l * 4, "Bitmap (%d to %d): %s", n, n + l * 32 - 1,
544 bitrange(tvb, p, l, n));
547 proto_tree_add_text(field_tree, tvb, p,
548 4 + l * 4, "Bitmap (%d to %d): %s", n, n + l * 32 - 1,
549 bitrange(tvb, p + 4, l, n));
552 n += l * 32 + i * 32;
554 off = tvb_length_remaining(tvb, offset);
556 case NI_QTYPE_DNSNAME:
557 proto_tree_add_text(tree, tvb, offset + sizeof(*ni),
558 sizeof(gint32), "TTL: %d", (gint32)tvb_get_ntohl(tvb, offset + sizeof *ni));
559 tf = proto_tree_add_text(tree, tvb,
560 offset + sizeof(*ni) + sizeof(guint32),
561 tvb_length_remaining(tvb, offset),
563 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_nodedns);
564 /* XXXX - clean this up when packet-dns.c has been tvbuffified */
565 tvb_compat(tvb, &pd, &top_level_offset);
566 j = offset + sizeof (*ni) + sizeof(guint32);
567 while (j < tvb_length(tvb)) {
568 l = get_dns_name(pd, top_level_offset + j,
569 top_level_offset + offset + sizeof (*ni) + sizeof(guint32),
570 dname,sizeof(dname));
571 if (tvb_bytes_exist(tvb, top_level_offset + j + l, 1) &&
572 tvb_get_guint8(tvb, top_level_offset + j + l) == 0) {
574 proto_tree_add_text(field_tree, tvb, j, l,
575 "DNS label: %s (truncated)", dname);
577 proto_tree_add_text(field_tree, tvb, j, l,
578 "DNS label: %s", dname);
582 off = tvb_length_remaining(tvb, offset);
584 case NI_QTYPE_NODEADDR:
585 n = tvb_length_remaining(tvb, offset + sizeof(*ni));
586 n /= sizeof(gint32) + sizeof(struct e_in6_addr);
587 tf = proto_tree_add_text(tree, tvb,
588 offset + sizeof(*ni), tvb_length_remaining(tvb, offset), "IPv6 node addresses");
589 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_node6);
590 p = offset + sizeof (*ni);
591 for (i = 0; i < n; i++) {
592 struct e_in6_addr e_in6_addr;
594 ttl = (gint32)tvb_get_ntohl(tvb, p);
595 tvb_memcpy(tvb, (guint8 *)&e_in6_addr, p + sizeof ttl, sizeof e_in6_addr);
596 proto_tree_add_text(field_tree, tvb,
597 p, sizeof(struct e_in6_addr) + sizeof(gint32),
598 "%s (TTL %d)", ip6_to_str(&e_in6_addr), ttl);
599 p += sizeof(struct e_in6_addr) + sizeof(gint32);
601 off = tvb_length_remaining(tvb, offset);
603 case NI_QTYPE_IPV4ADDR:
604 n = tvb_length_remaining(tvb, offset + sizeof(*ni));
605 n /= sizeof(gint32) + sizeof(guint32);
606 tf = proto_tree_add_text(tree, tvb,
607 offset + sizeof(*ni), tvb_length_remaining(tvb, offset), "IPv4 node addresses");
608 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_node4);
609 p = offset + sizeof *ni;
610 for (i = 0; i < n; i++) {
611 tvb_memcpy(tvb, ipaddr, sizeof(gint32) + p, 4);
612 proto_tree_add_text(field_tree, tvb,
613 p, sizeof(guint32), "%s (TTL %d)", ip_to_str(ipaddr), tvb_get_ntohl(tvb, p));
614 p += sizeof(gint32) + sizeof(guint32);
616 off = tvb_length_remaining(tvb, offset);
622 /* the rest of data */
623 dissect_data(tvb_new_subset(tvb, offset + off, -1, -1), 0, pinfo, tree);
627 dissect_rrenum(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
629 proto_tree *field_tree, *opt_tree;
631 struct icmp6_router_renum icmp6_router_renum, *rr;
632 struct rr_pco_match rr_pco_match, *match;
633 struct rr_pco_use rr_pco_use, *use;
638 rr = &icmp6_router_renum;
639 tvb_memcpy(tvb, (guint8 *)rr, offset, sizeof *rr);
640 proto_tree_add_text(tree, tvb,
641 offset + offsetof(struct icmp6_router_renum, rr_seqnum), 4,
642 "Sequence number: 0x%08x", pntohl(&rr->rr_seqnum));
643 proto_tree_add_text(tree, tvb,
644 offset + offsetof(struct icmp6_router_renum, rr_segnum), 1,
645 "Segment number: 0x%02x", rr->rr_segnum);
647 flagoff = offset + offsetof(struct icmp6_router_renum, rr_flags);
648 flags = tvb_get_guint8(tvb, flagoff);
649 tf = proto_tree_add_text(tree, tvb, flagoff, 1,
650 "Flags: 0x%02x", flags);
651 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
652 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
653 decode_boolean_bitfield(flags, 0x80, 8,
654 "Test command", "Not test command"));
655 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
656 decode_boolean_bitfield(flags, 0x40, 8,
657 "Result requested", "Result not requested"));
658 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
659 decode_boolean_bitfield(flags, 0x20, 8,
660 "All interfaces", "Not all interfaces"));
661 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
662 decode_boolean_bitfield(flags, 0x10, 8,
663 "Site specific", "Not site specific"));
664 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
665 decode_boolean_bitfield(flags, 0x08, 8,
666 "Processed previously", "Complete result"));
668 proto_tree_add_text(tree, tvb,
669 offset + offsetof(struct icmp6_router_renum, rr_maxdelay), 2,
670 "Max delay: 0x%04x", pntohs(&rr->rr_maxdelay));
671 dissect_data(tvb_new_subset(tvb, offset + sizeof(*rr), -1, -1), 0, pinfo, tree); /*XXX*/
673 if (rr->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) {
674 off = offset + sizeof(*rr);
675 match = &rr_pco_match;
676 tvb_memcpy(tvb, (guint8 *)match, off, sizeof *match);
677 tf = proto_tree_add_text(tree, tvb, off, sizeof(*match),
678 "Match-Prefix: %s/%u (%u-%u)", ip6_to_str(&match->rpm_prefix),
679 match->rpm_matchlen, match->rpm_minlen, match->rpm_maxlen);
680 opt_tree = proto_item_add_subtree(tf, ett_icmpv6opt);
681 proto_tree_add_text(opt_tree, tvb,
682 off + offsetof(struct rr_pco_match, rpm_code),
683 sizeof(match->rpm_code), "OpCode: %s (%u)",
684 val_to_str(match->rpm_code, names_rrenum_matchcode, "Unknown"),
686 proto_tree_add_text(opt_tree, tvb,
687 off + offsetof(struct rr_pco_match, rpm_len),
688 sizeof(match->rpm_len), "OpLength: %u (%u octets)",
689 match->rpm_len, match->rpm_len * 8);
690 proto_tree_add_text(opt_tree, tvb,
691 off + offsetof(struct rr_pco_match, rpm_ordinal),
692 sizeof(match->rpm_ordinal), "Ordinal: %u", match->rpm_ordinal);
693 proto_tree_add_text(opt_tree, tvb,
694 off + offsetof(struct rr_pco_match, rpm_matchlen),
695 sizeof(match->rpm_matchlen), "MatchLen: %u", match->rpm_matchlen);
696 proto_tree_add_text(opt_tree, tvb,
697 off + offsetof(struct rr_pco_match, rpm_minlen),
698 sizeof(match->rpm_minlen), "MinLen: %u", match->rpm_minlen);
699 proto_tree_add_text(opt_tree, tvb,
700 off + offsetof(struct rr_pco_match, rpm_maxlen),
701 sizeof(match->rpm_maxlen), "MaxLen: %u", match->rpm_maxlen);
702 proto_tree_add_text(opt_tree, tvb,
703 off + offsetof(struct rr_pco_match, rpm_prefix),
704 sizeof(match->rpm_prefix), "MatchPrefix: %s",
705 ip6_to_str(&match->rpm_prefix));
707 off += sizeof(*match);
709 for (l = match->rpm_len * 8 - sizeof(*match);
710 l >= sizeof(*use); l -= sizeof(*use), off += sizeof(*use)) {
711 tvb_memcpy(tvb, (guint8 *)use, off, sizeof *use);
712 tf = proto_tree_add_text(tree, tvb, off, sizeof(*use),
713 "Use-Prefix: %s/%u (keep %u)", ip6_to_str(&use->rpu_prefix),
714 use->rpu_uselen, use->rpu_keeplen);
715 opt_tree = proto_item_add_subtree(tf, ett_icmpv6opt);
716 proto_tree_add_text(opt_tree, tvb,
717 off + offsetof(struct rr_pco_use, rpu_uselen),
718 sizeof(use->rpu_uselen), "UseLen: %u", use->rpu_uselen);
719 proto_tree_add_text(opt_tree, tvb,
720 off + offsetof(struct rr_pco_use, rpu_keeplen),
721 sizeof(use->rpu_keeplen), "KeepLen: %u", use->rpu_keeplen);
722 tf = proto_tree_add_text(opt_tree, tvb,
723 flagoff = off + offsetof(struct rr_pco_use, rpu_ramask),
724 sizeof(use->rpu_ramask), "FlagMask: 0x%x", use->rpu_ramask);
725 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
726 flags = tvb_get_guint8(tvb, flagoff);
727 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
728 decode_boolean_bitfield(flags,
729 ICMP6_RR_PCOUSE_RAFLAGS_ONLINK, 8,
730 "Onlink", "Not onlink"));
731 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
732 decode_boolean_bitfield(flags,
733 ICMP6_RR_PCOUSE_RAFLAGS_AUTO, 8,
734 "Auto", "Not auto"));
735 tf = proto_tree_add_text(opt_tree, tvb,
736 flagoff = off + offsetof(struct rr_pco_use, rpu_raflags),
737 sizeof(use->rpu_raflags), "RAFlags: 0x%x", use->rpu_raflags);
738 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
739 flags = tvb_get_guint8(tvb, flagoff);
740 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
741 decode_boolean_bitfield(flags,
742 ICMP6_RR_PCOUSE_RAFLAGS_ONLINK, 8,
743 "Onlink", "Not onlink"));
744 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
745 decode_boolean_bitfield(flags,
746 ICMP6_RR_PCOUSE_RAFLAGS_AUTO, 8, "Auto", "Not auto"));
747 if (pntohl(&use->rpu_vltime) == 0xffffffff)
748 proto_tree_add_text(opt_tree, tvb,
749 off + offsetof(struct rr_pco_use, rpu_vltime),
750 sizeof(use->rpu_vltime), "Valid Lifetime: infinity");
752 proto_tree_add_text(opt_tree, tvb,
753 off + offsetof(struct rr_pco_use, rpu_vltime),
754 sizeof(use->rpu_vltime), "Valid Lifetime: %u",
755 pntohl(&use->rpu_vltime));
756 if (pntohl(&use->rpu_pltime) == 0xffffffff)
757 proto_tree_add_text(opt_tree, tvb,
758 off + offsetof(struct rr_pco_use, rpu_pltime),
759 sizeof(use->rpu_pltime), "Preferred Lifetime: infinity");
761 proto_tree_add_text(opt_tree, tvb,
762 off + offsetof(struct rr_pco_use, rpu_pltime),
763 sizeof(use->rpu_pltime), "Preferred Lifetime: %u",
764 pntohl(&use->rpu_pltime));
765 tf = proto_tree_add_text(opt_tree, tvb,
766 flagoff = off + offsetof(struct rr_pco_use, rpu_flags),
767 sizeof(use->rpu_flags), "Flags: 0x%08x",
768 pntohl(&use->rpu_flags));
769 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
770 flags = tvb_get_guint8(tvb, flagoff);
771 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
772 decode_boolean_bitfield(flags,
773 ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, 32,
774 "Decrement valid lifetime", "No decrement valid lifetime"));
775 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
776 decode_boolean_bitfield(flags,
777 ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, 32,
778 "Decrement preferred lifetime",
779 "No decrement preferred lifetime"));
780 proto_tree_add_text(opt_tree, tvb,
781 off + offsetof(struct rr_pco_use, rpu_prefix),
782 sizeof(use->rpu_prefix), "UsePrefix: %s",
783 ip6_to_str(&use->rpu_prefix));
790 dissect_icmpv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
792 proto_tree *icmp6_tree, *field_tree;
793 proto_item *ti, *tf = NULL;
794 struct icmp6_hdr icmp6_hdr, *dp;
795 struct icmp6_nodeinfo *ni = NULL;
796 char *codename, *typename;
797 char *colcodename, *coltypename;
799 guint length, reported_length;
802 guint16 cksum, computed_cksum;
807 tvb_memcpy(tvb, (guint8 *)&icmp6_hdr, offset, sizeof icmp6_hdr);
809 codename = typename = colcodename = coltypename = "Unknown";
811 switch (dp->icmp6_type) {
812 case ICMP6_DST_UNREACH:
813 typename = coltypename = "Unreachable";
814 switch (dp->icmp6_code) {
815 case ICMP6_DST_UNREACH_NOROUTE:
816 codename = colcodename = "Route unreachable";
818 case ICMP6_DST_UNREACH_ADMIN:
819 codename = colcodename = "Administratively prohibited";
821 case ICMP6_DST_UNREACH_NOTNEIGHBOR:
822 codename = colcodename = "Not a neighbor";
824 case ICMP6_DST_UNREACH_ADDR:
825 codename = colcodename = "Address unreachable";
827 case ICMP6_DST_UNREACH_NOPORT:
828 codename = colcodename = "Port unreachable";
832 case ICMP6_PACKET_TOO_BIG:
833 typename = coltypename = "Too big";
834 codename = colcodename = NULL;
836 case ICMP6_TIME_EXCEEDED:
837 typename = coltypename = "Time exceeded";
838 switch (dp->icmp6_code) {
839 case ICMP6_TIME_EXCEED_TRANSIT:
840 codename = colcodename = "In-transit";
842 case ICMP6_TIME_EXCEED_REASSEMBLY:
843 codename = colcodename = "Reassembly";
847 case ICMP6_PARAM_PROB:
848 typename = coltypename = "Parameter problem";
849 switch (dp->icmp6_code) {
850 case ICMP6_PARAMPROB_HEADER:
851 codename = colcodename = "Header";
853 case ICMP6_PARAMPROB_NEXTHEADER:
854 codename = colcodename = "Next header";
856 case ICMP6_PARAMPROB_OPTION:
857 codename = colcodename = "Option";
861 case ICMP6_ECHO_REQUEST:
862 typename = coltypename = "Echo request";
863 codename = colcodename = NULL;
865 case ICMP6_ECHO_REPLY:
866 typename = coltypename = "Echo reply";
867 codename = colcodename = NULL;
869 case ICMP6_MEMBERSHIP_QUERY:
870 typename = coltypename = "Multicast listener query";
871 codename = colcodename = NULL;
873 case ICMP6_MEMBERSHIP_REPORT:
874 typename = coltypename = "Multicast listener report";
875 codename = colcodename = NULL;
877 case ICMP6_MEMBERSHIP_REDUCTION:
878 typename = coltypename = "Multicast listener done";
879 codename = colcodename = NULL;
881 case ND_ROUTER_SOLICIT:
882 typename = coltypename = "Router solicitation";
883 codename = colcodename = NULL;
884 len = sizeof(struct nd_router_solicit);
886 case ND_ROUTER_ADVERT:
887 typename = coltypename = "Router advertisement";
888 codename = colcodename = NULL;
889 len = sizeof(struct nd_router_advert);
891 case ND_NEIGHBOR_SOLICIT:
892 typename = coltypename = "Neighbor solicitation";
893 codename = colcodename = NULL;
894 len = sizeof(struct nd_neighbor_solicit);
896 case ND_NEIGHBOR_ADVERT:
897 typename = coltypename = "Neighbor advertisement";
898 codename = colcodename = NULL;
899 len = sizeof(struct nd_neighbor_advert);
902 typename = coltypename = "Redirect";
903 codename = colcodename = NULL;
904 len = sizeof(struct nd_redirect);
906 case ICMP6_ROUTER_RENUMBERING:
907 typename = coltypename = "Router renumbering";
908 switch (dp->icmp6_code) {
909 case ICMP6_ROUTER_RENUMBERING_COMMAND:
910 codename = colcodename = "Command";
912 case ICMP6_ROUTER_RENUMBERING_RESULT:
913 codename = colcodename = "Result";
915 case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
916 codename = colcodename = "Sequence number reset";
919 len = sizeof(struct icmp6_router_renum);
923 ni = (struct icmp6_nodeinfo *)dp;
924 if (ni->ni_type == ICMP6_NI_QUERY) {
925 typename = coltypename = "Node information query";
926 switch (ni->ni_code) {
927 case ICMP6_NI_SUBJ_IPV6:
928 codename = "Query subject = IPv6 addresses";
930 case ICMP6_NI_SUBJ_FQDN:
931 if (tvb_bytes_exist(tvb, offset, sizeof(*ni)))
932 codename = "Query subject = DNS name";
934 codename = "Query subject = empty";
936 case ICMP6_NI_SUBJ_IPV4:
937 codename = "Query subject = IPv4 addresses";
941 typename = coltypename = "Node information reply";
942 switch (ni->ni_code) {
943 case ICMP6_NI_SUCCESS:
944 codename = "Successful";
946 case ICMP6_NI_REFUSED:
947 codename = "Refused";
949 case ICMP6_NI_UNKNOWN:
950 codename = "Unknown query type";
954 colcodename = val_to_str(pntohs(&ni->ni_qtype), names_nodeinfo_qtype,
956 len = sizeof(struct icmp6_nodeinfo);
960 if (check_col(pinfo->fd, COL_PROTOCOL))
961 col_set_str(pinfo->fd, COL_PROTOCOL, "ICMPv6");
962 if (check_col(pinfo->fd, COL_INFO)) {
963 char typebuf[256], codebuf[256];
965 if (coltypename && strcmp(coltypename, "Unknown") == 0) {
966 snprintf(typebuf, sizeof(typebuf), "Unknown (0x%02x)",
968 coltypename = typebuf;
970 if (colcodename && strcmp(colcodename, "Unknown") == 0) {
971 snprintf(codebuf, sizeof(codebuf), "Unknown (0x%02x)",
973 colcodename = codebuf;
976 col_add_fstr(pinfo->fd, COL_INFO, "%s (%s)", coltypename, colcodename);
978 col_add_fstr(pinfo->fd, COL_INFO, "%s", coltypename);
983 /* !!! specify length */
984 ti = proto_tree_add_item(tree, proto_icmpv6, tvb, offset, len, FALSE);
985 icmp6_tree = proto_item_add_subtree(ti, ett_icmpv6);
987 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_type, tvb,
988 offset + offsetof(struct icmp6_hdr, icmp6_type), 1,
990 "Type: %u (%s)", dp->icmp6_type, typename);
992 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_code, tvb,
993 offset + offsetof(struct icmp6_hdr, icmp6_code), 1,
995 "Code: %u (%s)", dp->icmp6_code, codename);
997 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_code, tvb,
998 offset + offsetof(struct icmp6_hdr, icmp6_code), 1,
1000 "Code: %u", dp->icmp6_code);
1002 cksum = (guint16)htons(dp->icmp6_cksum);
1003 length = tvb_length(tvb);
1004 reported_length = tvb_reported_length(tvb);
1005 if (!pinfo->fragmented && length >= reported_length) {
1006 /* The packet isn't part of a fragmented datagram and isn't
1007 truncated, so we can checksum it. */
1009 /* Set up the fields of the pseudo-header. */
1010 cksum_vec[0].ptr = pinfo->src.data;
1011 cksum_vec[0].len = pinfo->src.len;
1012 cksum_vec[1].ptr = pinfo->dst.data;
1013 cksum_vec[1].len = pinfo->dst.len;
1014 cksum_vec[2].ptr = (const guint8 *)&phdr;
1015 phdr[0] = htonl(tvb_reported_length(tvb));
1016 phdr[1] = htonl(IP_PROTO_ICMPV6);
1017 cksum_vec[2].len = 8;
1018 cksum_vec[3].len = tvb_reported_length(tvb);
1019 cksum_vec[3].ptr = tvb_get_ptr(tvb, offset, cksum_vec[3].len);
1020 computed_cksum = in_cksum(cksum_vec, 4);
1021 if (computed_cksum == 0) {
1022 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_checksum,
1024 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1026 "Checksum: 0x%04x (correct)", cksum);
1028 proto_tree_add_boolean_hidden(icmp6_tree, hf_icmpv6_checksum_bad,
1030 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1032 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_checksum,
1034 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1036 "Checksum: 0x%04x (incorrect, should be 0x%04x)",
1037 cksum, in_cksum_shouldbe(cksum, computed_cksum));
1040 proto_tree_add_uint(icmp6_tree, hf_icmpv6_checksum, tvb,
1041 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1046 next_tvb = tvb_new_subset(tvb, offset + sizeof(*dp), -1, -1);
1047 switch (dp->icmp6_type) {
1048 case ICMP6_DST_UNREACH:
1049 case ICMP6_TIME_EXCEEDED:
1050 /* tiny sanity check */
1051 if ((tvb_get_guint8(tvb, offset + sizeof(*dp)) & 0xf0) == 0x60) {
1052 /* The invoking packet is an IPv6 datagram; dissect it.
1054 Set the columns non-writable, so that the packet list
1055 shows this as an ICMPv6 packet, not as the type of packet
1056 for which the ICMPv6 packet was generated. */
1057 col_set_writable(pinfo->fd, FALSE);
1059 call_dissector(ipv6_handle, next_tvb, pinfo, icmp6_tree);
1061 dissect_data(next_tvb, 0, pinfo, icmp6_tree);
1064 case ICMP6_PACKET_TOO_BIG:
1065 proto_tree_add_text(icmp6_tree, tvb,
1066 offset + offsetof(struct icmp6_hdr, icmp6_mtu), 4,
1067 "MTU: %u", pntohl(&dp->icmp6_mtu));
1068 /* tiny sanity check */
1069 if ((tvb_get_guint8(tvb, offset + sizeof(*dp)) & 0xf0) == 0x60) {
1070 /* The invoking packet is an IPv6 datagram; dissect it.
1072 Set the columns non-writable, so that the packet list
1073 shows this as an ICMPv6 packet, not as the type of packet
1074 for which the ICMPv6 packet was generated. */
1075 col_set_writable(pinfo->fd, FALSE);
1077 call_dissector(ipv6_handle, next_tvb, pinfo, icmp6_tree);
1079 dissect_data(next_tvb, 0, pinfo, icmp6_tree);
1082 case ICMP6_PARAM_PROB:
1083 proto_tree_add_text(icmp6_tree, tvb,
1084 offset + offsetof(struct icmp6_hdr, icmp6_pptr), 4,
1085 "Problem pointer: 0x%04x", pntohl(&dp->icmp6_pptr));
1086 /* tiny sanity check */
1087 if ((tvb_get_guint8(tvb, offset + sizeof(*dp)) & 0xf0) == 0x60) {
1088 /* The invoking packet is an IPv6 datagram; dissect it.
1090 Set the columns non-writable, so that the packet list
1091 shows this as an ICMPv6 packet, not as the type of packet
1092 for which the ICMPv6 packet was generated. */
1093 col_set_writable(pinfo->fd, FALSE);
1095 call_dissector(ipv6_handle, next_tvb, pinfo, icmp6_tree);
1097 dissect_data(next_tvb, 0, pinfo, icmp6_tree);
1100 case ICMP6_ECHO_REQUEST:
1101 case ICMP6_ECHO_REPLY:
1102 proto_tree_add_text(icmp6_tree, tvb,
1103 offset + offsetof(struct icmp6_hdr, icmp6_id), 2,
1104 "ID: 0x%04x", (guint16)ntohs(dp->icmp6_id));
1105 proto_tree_add_text(icmp6_tree, tvb,
1106 offset + offsetof(struct icmp6_hdr, icmp6_seq), 2,
1107 "Sequence: 0x%04x", (guint16)ntohs(dp->icmp6_seq));
1108 dissect_data(next_tvb, 0, pinfo, icmp6_tree);
1110 case ICMP6_MEMBERSHIP_QUERY:
1111 case ICMP6_MEMBERSHIP_REPORT:
1112 case ICMP6_MEMBERSHIP_REDUCTION:
1113 proto_tree_add_text(icmp6_tree, tvb,
1114 offset + offsetof(struct icmp6_hdr, icmp6_maxdelay), 2,
1115 "Maximum response delay: %u",
1116 (guint16)ntohs(dp->icmp6_maxdelay));
1117 proto_tree_add_text(icmp6_tree, tvb, offset + sizeof(*dp), 16,
1118 "Multicast Address: %s",
1119 ip6_to_str((struct e_in6_addr *)(tvb_get_ptr(tvb, offset + sizeof *dp, sizeof (struct e_in6_addr)))));
1121 case ND_ROUTER_SOLICIT:
1122 dissect_icmpv6opt(tvb, offset + sizeof(*dp), pinfo, icmp6_tree);
1124 case ND_ROUTER_ADVERT:
1126 struct nd_router_advert nd_router_advert, *ra;
1130 ra = &nd_router_advert;
1131 tvb_memcpy(tvb, (guint8 *)ra, offset, sizeof *ra);
1132 proto_tree_add_text(icmp6_tree, tvb,
1133 offset + offsetof(struct nd_router_advert, nd_ra_curhoplimit),
1134 1, "Cur hop limit: %u", ra->nd_ra_curhoplimit);
1136 flagoff = offset + offsetof(struct nd_router_advert, nd_ra_flags_reserved);
1137 ra_flags = tvb_get_guint8(tvb, flagoff);
1138 tf = proto_tree_add_text(icmp6_tree, tvb, flagoff, 1, "Flags: 0x%02x", ra_flags);
1139 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1140 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1141 decode_boolean_bitfield(ra_flags,
1142 0x80, 8, "Managed", "Not managed"));
1143 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1144 decode_boolean_bitfield(ra_flags,
1145 0x40, 8, "Other", "Not other"));
1146 /* BT INSERT BEGIN */
1147 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1148 decode_boolean_bitfield(ra_flags,
1149 0x20, 8, "Home Agent", "Not Home Agent"));
1151 proto_tree_add_text(icmp6_tree, tvb,
1152 offset + offsetof(struct nd_router_advert, nd_ra_router_lifetime),
1153 2, "Router lifetime: %u",
1154 (guint16)ntohs(ra->nd_ra_router_lifetime));
1155 proto_tree_add_text(icmp6_tree, tvb,
1156 offset + offsetof(struct nd_router_advert, nd_ra_reachable), 4,
1157 "Reachable time: %u", pntohl(&ra->nd_ra_reachable));
1158 proto_tree_add_text(icmp6_tree, tvb,
1159 offset + offsetof(struct nd_router_advert, nd_ra_retransmit), 4,
1160 "Retrans time: %u", pntohl(&ra->nd_ra_retransmit));
1161 dissect_icmpv6opt(tvb, offset + sizeof(struct nd_router_advert), pinfo, icmp6_tree);
1164 case ND_NEIGHBOR_SOLICIT:
1166 struct nd_neighbor_solicit nd_neighbor_solicit, *ns;
1168 ns = &nd_neighbor_solicit;
1169 tvb_memcpy(tvb, (guint8 *)ns, offset, sizeof *ns);
1170 proto_tree_add_text(icmp6_tree, tvb,
1171 offset + offsetof(struct nd_neighbor_solicit, nd_ns_target), 16,
1174 get_hostname6(&ns->nd_ns_target),
1178 ip6_to_str(&ns->nd_ns_target));
1180 dissect_icmpv6opt(tvb, offset + sizeof(*ns), pinfo, icmp6_tree);
1183 case ND_NEIGHBOR_ADVERT:
1185 int flagoff, targetoff;
1187 struct e_in6_addr na_target;
1189 flagoff = offset + offsetof(struct nd_neighbor_advert, nd_na_flags_reserved);
1190 na_flags = tvb_get_ntohl(tvb, flagoff);
1192 tf = proto_tree_add_text(icmp6_tree, tvb, flagoff, 4, "Flags: 0x%08x", na_flags);
1193 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1194 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
1195 decode_boolean_bitfield(na_flags,
1196 ND_NA_FLAG_ROUTER, 32, "Router", "Not router"));
1197 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
1198 decode_boolean_bitfield(na_flags,
1199 ND_NA_FLAG_SOLICITED, 32, "Solicited", "Not adverted"));
1200 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
1201 decode_boolean_bitfield(na_flags,
1202 ND_NA_FLAG_OVERRIDE, 32, "Override", "Not override"));
1204 targetoff = offset + offsetof(struct nd_neighbor_advert, nd_na_target);
1205 tvb_memcpy(tvb, (guint8 *)&na_target, targetoff, sizeof na_target);
1206 proto_tree_add_text(icmp6_tree, tvb, targetoff, 16,
1209 get_hostname6(&na_target),
1213 ip6_to_str(&na_target));
1215 dissect_icmpv6opt(tvb, offset + sizeof(struct nd_neighbor_advert), pinfo, icmp6_tree);
1220 struct nd_redirect nd_redirect, *rd;
1223 tvb_memcpy(tvb, (guint8 *)rd, offset, sizeof *rd);
1224 proto_tree_add_text(icmp6_tree, tvb,
1225 offset + offsetof(struct nd_redirect, nd_rd_target), 16,
1228 get_hostname6(&rd->nd_rd_target),
1232 ip6_to_str(&rd->nd_rd_target));
1234 proto_tree_add_text(icmp6_tree, tvb,
1235 offset + offsetof(struct nd_redirect, nd_rd_dst), 16,
1237 "Destination: %s (%s)",
1238 get_hostname6(&rd->nd_rd_dst),
1242 ip6_to_str(&rd->nd_rd_dst));
1244 dissect_icmpv6opt(tvb, offset + sizeof(*rd), pinfo, icmp6_tree);
1247 case ICMP6_ROUTER_RENUMBERING:
1248 dissect_rrenum(tvb, offset, pinfo, icmp6_tree);
1250 case ICMP6_NI_QUERY:
1251 case ICMP6_NI_REPLY:
1252 ni = (struct icmp6_nodeinfo *)dp;
1253 proto_tree_add_text(icmp6_tree, tvb,
1254 offset + offsetof(struct icmp6_nodeinfo, ni_qtype),
1255 sizeof(ni->ni_qtype),
1256 "Query type: 0x%04x (%s)", pntohs(&ni->ni_qtype),
1257 val_to_str(pntohs(&ni->ni_qtype), names_nodeinfo_qtype,
1259 dissect_nodeinfo(tvb, offset, pinfo, icmp6_tree);
1262 dissect_data(next_tvb, 0, pinfo, tree);
1269 proto_register_icmpv6(void)
1271 static hf_register_info hf[] = {
1273 { "Type", "icmpv6.type", FT_UINT8, BASE_DEC, NULL, 0x0,
1276 { "Code", "icmpv6.code", FT_UINT8, BASE_DEC, NULL, 0x0,
1278 { &hf_icmpv6_checksum,
1279 { "Checksum", "icmpv6.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
1281 { &hf_icmpv6_checksum_bad,
1282 { "Bad Checksum", "icmpv6.checksum_bad", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1285 static gint *ett[] = {
1290 &ett_nodeinfo_subject4,
1291 &ett_nodeinfo_subject6,
1292 &ett_nodeinfo_node4,
1293 &ett_nodeinfo_node6,
1294 &ett_nodeinfo_nodebitmap,
1295 &ett_nodeinfo_nodedns,
1298 proto_icmpv6 = proto_register_protocol("Internet Control Message Protocol v6",
1299 "ICMPv6", "icmpv6");
1300 proto_register_field_array(proto_icmpv6, hf, array_length(hf));
1301 proto_register_subtree_array(ett, array_length(ett));
1305 proto_reg_handoff_icmpv6(void)
1307 dissector_add("ip.proto", IP_PROTO_ICMPV6, dissect_icmpv6, proto_icmpv6);
1310 * Get a handle for the IPv6 dissector.
1312 ipv6_handle = find_dissector("ipv6");