2 * Routines for ICMPv6 packet disassembly
4 * $Id: packet-icmpv6.c,v 1.43 2001/05/27 04:14:53 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_contained_icmpv6(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
106 address save_net_src;
107 address save_net_dst;
111 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
113 /* tiny sanity check */
114 if ((tvb_get_guint8(tvb, offset) & 0xf0) == 0x60) {
115 /* The contained packet is an IPv6 datagram; dissect it.
117 Set the columns non-writable, so that the packet list
118 shows this as an ICMPv6 packet, not as the type of packet
119 for which the ICMPv6 packet was generated. */
120 col_set_writable(pinfo->fd, FALSE);
122 /* Also, save the current values of the addresses, and restore
123 them when we're finished dissecting the contained packet, so
124 that the address columns in the summary don't reflect the
125 contained packet, but reflect this packet instead. */
126 save_dl_src = pinfo->dl_src;
127 save_dl_dst = pinfo->dl_dst;
128 save_net_src = pinfo->net_src;
129 save_net_dst = pinfo->net_dst;
130 save_src = pinfo->src;
131 save_dst = pinfo->dst;
133 /* Dissect the contained packet. */
134 call_dissector(ipv6_handle, next_tvb, pinfo, tree);
136 /* Restore the addresses. */
137 pinfo->dl_src = save_dl_src;
138 pinfo->dl_dst = save_dl_dst;
139 pinfo->net_src = save_net_src;
140 pinfo->net_dst = save_net_dst;
141 pinfo->src = save_src;
142 pinfo->dst = save_dst;
144 dissect_data(next_tvb, 0, pinfo, tree);
148 dissect_icmpv6opt(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
150 proto_tree *icmp6opt_tree, *field_tree;
152 struct nd_opt_hdr nd_opt_hdr, *opt;
160 if ((int)tvb_reported_length(tvb) <= offset)
161 return; /* No more options left */
164 tvb_memcpy(tvb, (guint8 *)opt, offset, sizeof *opt);
165 len = opt->nd_opt_len << 3;
167 /* !!! specify length */
168 ti = proto_tree_add_text(tree, tvb, offset, len, "ICMPv6 options");
169 icmp6opt_tree = proto_item_add_subtree(ti, ett_icmpv6opt);
171 switch (opt->nd_opt_type) {
172 case ND_OPT_SOURCE_LINKADDR:
173 typename = "Source link-layer address";
175 case ND_OPT_TARGET_LINKADDR:
176 typename = "Target link-layer address";
178 case ND_OPT_PREFIX_INFORMATION:
179 typename = "Prefix information";
181 case ND_OPT_REDIRECTED_HEADER:
182 typename = "Redirected header";
187 case ND_OPT_ADVERTISEMENT_INTERVAL:
188 typename = "Advertisement Interval";
190 case ND_OPT_HOME_AGENT_INFORMATION:
191 typename = "Home Agent Information";
195 typename = "Unknown";
199 proto_tree_add_text(icmp6opt_tree, tvb,
200 offset + offsetof(struct nd_opt_hdr, nd_opt_type), 1,
201 "Type: %u (%s)", opt->nd_opt_type, typename);
202 proto_tree_add_text(icmp6opt_tree, tvb,
203 offset + offsetof(struct nd_opt_hdr, nd_opt_len), 1,
204 "Length: %u bytes (%u)", opt->nd_opt_len << 3, opt->nd_opt_len);
207 switch (opt->nd_opt_type) {
208 case ND_OPT_SOURCE_LINKADDR:
209 case ND_OPT_TARGET_LINKADDR:
213 len = (opt->nd_opt_len << 3) - sizeof(*opt);
214 t = (char *)malloc(len * 3);
215 memset(t, 0, len * 3);
216 p = offset + sizeof(*opt);
217 for (i = 0; i < len; i++) {
220 sprintf(&t[i * 3], "%02x", tvb_get_guint8(tvb, p + i) & 0xff);
222 proto_tree_add_text(icmp6opt_tree, tvb,
223 offset + sizeof(*opt), len, "Link-layer address: %s", t);
226 case ND_OPT_PREFIX_INFORMATION:
228 struct nd_opt_prefix_info nd_opt_prefix_info, *pi;
231 pi = &nd_opt_prefix_info;
232 tvb_memcpy(tvb, (guint8 *)pi, offset, sizeof *pi);
233 proto_tree_add_text(icmp6opt_tree, tvb,
234 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_prefix_len),
235 1, "Prefix length: %u", pi->nd_opt_pi_prefix_len);
237 flagoff = offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_flags_reserved);
238 tf = proto_tree_add_text(icmp6opt_tree, tvb, flagoff, 1, "Flags: 0x%02x",
239 tvb_get_guint8(tvb, offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_flags_reserved)));
240 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
241 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
242 decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
243 0x80, 8, "Onlink", "Not onlink"));
244 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
245 decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
246 0x40, 8, "Auto", "Not auto"));
247 /* BT INSERT BEGIN */
248 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
249 decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
250 0x20, 8, "Router Address", "Not router address"));
252 proto_tree_add_text(icmp6opt_tree, tvb,
253 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_valid_time),
254 4, "Valid lifetime: 0x%08x",
255 pntohl(&pi->nd_opt_pi_valid_time));
256 proto_tree_add_text(icmp6opt_tree, tvb,
257 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_preferred_time),
258 4, "Preferred lifetime: 0x%08x",
259 pntohl(&pi->nd_opt_pi_preferred_time));
260 proto_tree_add_text(icmp6opt_tree, tvb,
261 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_prefix),
262 16, "Prefix: %s", ip6_to_str(&pi->nd_opt_pi_prefix));
265 case ND_OPT_REDIRECTED_HEADER:
266 proto_tree_add_text(icmp6opt_tree, tvb,
267 offset + 8, (opt->nd_opt_len << 3) - 8, "Redirected packet");
268 dissect_contained_icmpv6(tvb, offset + 8, pinfo, icmp6opt_tree);
271 proto_tree_add_text(icmp6opt_tree, tvb,
272 offset + offsetof(struct nd_opt_mtu, nd_opt_mtu_mtu), 4,
273 "MTU: %u", tvb_get_ntohl(tvb, offset + offsetof(struct nd_opt_mtu, nd_opt_mtu_mtu)));
275 /* BT INSERT BEGIN */
276 case ND_OPT_ADVERTISEMENT_INTERVAL:
277 proto_tree_add_text(icmp6opt_tree, tvb,
278 offset + offsetof(struct nd_opt_adv_int, nd_opt_adv_int_advint), 4,
279 "Advertisement Interval: %d",
280 tvb_get_ntohl(tvb, offset + offsetof(struct nd_opt_adv_int, nd_opt_adv_int_advint)));
282 case ND_OPT_HOME_AGENT_INFORMATION:
284 struct nd_opt_ha_info *pi = (struct nd_opt_ha_info *)opt;
285 proto_tree_add_text(icmp6opt_tree, tvb,
286 offset + offsetof(struct nd_opt_ha_info, nd_opt_ha_info_ha_pref),
287 2, "Home Agent Preference: %d",
288 pntohs(&pi->nd_opt_ha_info_ha_pref));
289 proto_tree_add_text(icmp6opt_tree, tvb,
290 offset + offsetof(struct nd_opt_ha_info, nd_opt_ha_info_ha_life),
291 2, "Home Agent Lifetime: %d",
292 pntohs(&pi->nd_opt_ha_info_ha_life));
298 if (opt->nd_opt_len == 0) {
299 proto_tree_add_text(icmp6opt_tree, tvb,
300 offset + offsetof(struct nd_opt_hdr, nd_opt_len), 1,
301 "Invalid option length: %u",
306 offset += (opt->nd_opt_len << 3);
311 * draft-ietf-ipngwg-icmp-name-lookups-07.txt
312 * Note that the packet format was changed several times in the past.
316 bitrange0(v, s, buf, buflen)
336 ep = buf + buflen - 1;
337 memset(buf, 0, buflen);
340 /* shift till we have 0x01 */
341 if ((v & 0x01) == 0) {
344 v >>= 4; off += 4; continue;
346 v >>= 3; off += 3; continue;
347 case 0x04: case 0x0c:
348 v >>= 2; off += 2; continue;
350 v >>= 1; off += 1; continue;
354 /* we have 0x01 with us */
355 for (i = 0; i < 32 - off; i++) {
356 if ((v & (0x01 << i)) == 0)
360 l = snprintf(p, ep - p, ",%d", s + off);
362 l = snprintf(p, ep - p, ",%d-%d", s + off,
376 bitrange(tvbuff_t *tvb, int offset, int l, int s)
378 static char buf[1024];
382 memset(buf, 0, sizeof(buf));
384 eq = buf + sizeof(buf) - 1;
385 for (i = 0; i < l; i++) {
386 if (bitrange0(tvb_get_ntohl(tvb, offset + i * 4), s + i * 4, q, eq - q) == NULL) {
387 if (q != buf && q + 5 < buf + sizeof(buf))
388 strncpy(q, ",...", 5);
397 dissect_nodeinfo(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
399 proto_tree *field_tree;
401 struct icmp6_nodeinfo icmp6_nodeinfo, *ni;
406 char dname[MAXDNAME];
409 int top_level_offset;
411 ni = &icmp6_nodeinfo;
412 tvb_memcpy(tvb, (guint8 *)ni, offset, sizeof *ni);
414 flags = pntohs(&ni->ni_flags);
415 tf = proto_tree_add_text(tree, tvb,
416 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
417 sizeof(ni->ni_flags), "Flags: 0x%04x", flags);
418 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_flag);
419 switch (pntohs(&ni->ni_qtype)) {
420 case NI_QTYPE_SUPTYPES:
421 if (ni->ni_type == ICMP6_NI_QUERY) {
422 proto_tree_add_text(field_tree, tvb,
423 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
424 sizeof(ni->ni_flags), "%s",
425 decode_boolean_bitfield(flags, NI_SUPTYPE_FLAG_COMPRESS, sizeof(flags) * 8,
426 "Compressed reply supported",
427 "No compressed reply support"));
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_SUPTYPE_FLAG_COMPRESS, sizeof(flags) * 8,
433 "Compressed", "Not compressed"));
436 case NI_QTYPE_DNSNAME:
437 if (ni->ni_type == ICMP6_NI_REPLY) {
438 proto_tree_add_text(field_tree, tvb,
439 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
440 sizeof(ni->ni_flags), "%s",
441 decode_boolean_bitfield(flags, NI_FQDN_FLAG_VALIDTTL, sizeof(flags) * 8,
442 "Valid TTL field", "Meaningless TTL field"));
445 case NI_QTYPE_NODEADDR:
446 proto_tree_add_text(field_tree, tvb,
447 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
448 sizeof(ni->ni_flags), "%s",
449 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_GLOBAL, sizeof(flags) * 8,
451 "Not global address"));
452 proto_tree_add_text(field_tree, tvb,
453 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
454 sizeof(ni->ni_flags), "%s",
455 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_SITELOCAL, sizeof(flags) * 8,
456 "Site-local address",
457 "Not site-local address"));
458 proto_tree_add_text(field_tree, tvb,
459 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
460 sizeof(ni->ni_flags), "%s",
461 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_LINKLOCAL, sizeof(flags) * 8,
462 "Link-local address",
463 "Not link-local address"));
464 proto_tree_add_text(field_tree, tvb,
465 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
466 sizeof(ni->ni_flags), "%s",
467 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_COMPAT, sizeof(flags) * 8,
468 "IPv4 compatible/mapped address",
469 "Not IPv4 compatible/mapped address"));
471 case NI_QTYPE_IPV4ADDR:
472 proto_tree_add_text(field_tree, tvb,
473 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
474 sizeof(ni->ni_flags), "%s",
475 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_ALL, sizeof(flags) * 8,
476 "All unicast address",
477 "Unicast addresses on the queried interface"));
478 proto_tree_add_text(field_tree, tvb,
479 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
480 sizeof(ni->ni_flags), "%s",
481 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_TRUNCATE, sizeof(flags) * 8,
482 "Truncated", "Not truncated"));
487 proto_tree_add_text(tree, tvb,
488 offset + offsetof(struct icmp6_nodeinfo, icmp6_ni_nonce[0]),
489 sizeof(ni->icmp6_ni_nonce), "Nonce: 0x%08x%08x",
490 pntohl(&ni->icmp6_ni_nonce[0]), pntohl(&ni->icmp6_ni_nonce[4]));
492 /* offset for "the rest of data" */
496 if (!tvb_bytes_exist(tvb, offset, sizeof(*ni)))
498 if (ni->ni_type == ICMP6_NI_QUERY) {
499 switch (ni->ni_code) {
500 case ICMP6_NI_SUBJ_IPV6:
501 n = tvb_length_remaining(tvb, offset + sizeof(*ni));
502 n /= sizeof(struct e_in6_addr);
503 tf = proto_tree_add_text(tree, tvb,
504 offset + sizeof(*ni), tvb_length_remaining(tvb, offset), "IPv6 subject addresses");
505 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_subject6);
506 p = offset + sizeof *ni;
507 for (i = 0; i < n; i++) {
508 struct e_in6_addr e_in6_addr;
509 tvb_memcpy(tvb, (guint8 *)&e_in6_addr, p, sizeof e_in6_addr);
510 proto_tree_add_text(field_tree, tvb,
511 p, sizeof(struct e_in6_addr),
512 "%s", ip6_to_str(&e_in6_addr));
513 p += sizeof(struct e_in6_addr);
515 off = tvb_length_remaining(tvb, offset);
517 case ICMP6_NI_SUBJ_FQDN:
518 /* XXXX - clean this up when packet-dns.c has been tvbuffified */
519 tvb_compat(tvb, &pd, &top_level_offset);
520 l = get_dns_name(pd, top_level_offset + offset + sizeof(*ni),
521 top_level_offset + offset + sizeof(*ni),
522 dname, sizeof(dname));
523 if (tvb_bytes_exist(tvb, offset + sizeof(*ni) + l, 1) &&
524 tvb_get_guint8(tvb, offset + sizeof(*ni) + l) == 0) {
526 proto_tree_add_text(tree, tvb, offset + sizeof(*ni), l,
527 "DNS label: %s (truncated)", dname);
529 proto_tree_add_text(tree, tvb, offset + sizeof(*ni), l,
530 "DNS label: %s", dname);
532 off = tvb_length_remaining(tvb, offset + sizeof(*ni) + l);
534 case ICMP6_NI_SUBJ_IPV4:
535 n = tvb_length_remaining(tvb, offset + sizeof(*ni));
536 n /= sizeof(guint32);
537 tf = proto_tree_add_text(tree, tvb,
538 offset + sizeof(*ni), tvb_length_remaining(tvb, offset), "IPv4 subject addresses");
539 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_subject4);
540 p = offset + sizeof *ni;
541 for (i = 0; i < n; i++) {
542 tvb_memcpy(tvb, ipaddr, p, 4);
543 proto_tree_add_text(field_tree, tvb,
544 p, sizeof(guint32), "%s", ip_to_str(ipaddr));
545 p += sizeof(guint32);
547 off = tvb_length_remaining(tvb, offset);
551 switch (pntohs(&ni->ni_qtype)) {
554 case NI_QTYPE_SUPTYPES:
555 p = offset + sizeof *ni;
556 tf = proto_tree_add_text(tree, tvb,
557 offset + sizeof(*ni), tvb_length_remaining(tvb, p),
558 "Supported type bitmap%s",
559 (flags & 0x0001) ? ", compressed" : "");
560 field_tree = proto_item_add_subtree(tf,
561 ett_nodeinfo_nodebitmap);
563 while (tvb_bytes_exist(tvb, p, sizeof(guint32))) { /* XXXX Check what? */
564 if ((flags & 0x0001) == 0) {
565 l = tvb_length_remaining(tvb, offset + sizeof(*ni));
566 l /= sizeof(guint32);
569 l = tvb_get_ntohs(tvb, p);
570 i = tvb_get_ntohs(tvb, p + sizeof(guint16)); /*skip*/
572 if (n + l * 32 > (1 << 16))
574 if (n + (l + i) * 32 > (1 << 16))
576 if ((flags & 0x0001) == 0) {
577 proto_tree_add_text(field_tree, tvb, p,
578 l * 4, "Bitmap (%d to %d): %s", n, n + l * 32 - 1,
579 bitrange(tvb, p, l, n));
582 proto_tree_add_text(field_tree, tvb, p,
583 4 + l * 4, "Bitmap (%d to %d): %s", n, n + l * 32 - 1,
584 bitrange(tvb, p + 4, l, n));
587 n += l * 32 + i * 32;
589 off = tvb_length_remaining(tvb, offset);
591 case NI_QTYPE_DNSNAME:
592 proto_tree_add_text(tree, tvb, offset + sizeof(*ni),
593 sizeof(gint32), "TTL: %d", (gint32)tvb_get_ntohl(tvb, offset + sizeof *ni));
594 tf = proto_tree_add_text(tree, tvb,
595 offset + sizeof(*ni) + sizeof(guint32),
596 tvb_length_remaining(tvb, offset),
598 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_nodedns);
599 /* XXXX - clean this up when packet-dns.c has been tvbuffified */
600 tvb_compat(tvb, &pd, &top_level_offset);
601 j = offset + sizeof (*ni) + sizeof(guint32);
602 while (j < tvb_length(tvb)) {
603 l = get_dns_name(pd, top_level_offset + j,
604 top_level_offset + offset + sizeof (*ni) + sizeof(guint32),
605 dname,sizeof(dname));
606 if (tvb_bytes_exist(tvb, top_level_offset + j + l, 1) &&
607 tvb_get_guint8(tvb, top_level_offset + j + l) == 0) {
609 proto_tree_add_text(field_tree, tvb, j, l,
610 "DNS label: %s (truncated)", dname);
612 proto_tree_add_text(field_tree, tvb, j, l,
613 "DNS label: %s", dname);
617 off = tvb_length_remaining(tvb, offset);
619 case NI_QTYPE_NODEADDR:
620 n = tvb_length_remaining(tvb, offset + sizeof(*ni));
621 n /= sizeof(gint32) + sizeof(struct e_in6_addr);
622 tf = proto_tree_add_text(tree, tvb,
623 offset + sizeof(*ni), tvb_length_remaining(tvb, offset), "IPv6 node addresses");
624 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_node6);
625 p = offset + sizeof (*ni);
626 for (i = 0; i < n; i++) {
627 struct e_in6_addr e_in6_addr;
629 ttl = (gint32)tvb_get_ntohl(tvb, p);
630 tvb_memcpy(tvb, (guint8 *)&e_in6_addr, p + sizeof ttl, sizeof e_in6_addr);
631 proto_tree_add_text(field_tree, tvb,
632 p, sizeof(struct e_in6_addr) + sizeof(gint32),
633 "%s (TTL %d)", ip6_to_str(&e_in6_addr), ttl);
634 p += sizeof(struct e_in6_addr) + sizeof(gint32);
636 off = tvb_length_remaining(tvb, offset);
638 case NI_QTYPE_IPV4ADDR:
639 n = tvb_length_remaining(tvb, offset + sizeof(*ni));
640 n /= sizeof(gint32) + sizeof(guint32);
641 tf = proto_tree_add_text(tree, tvb,
642 offset + sizeof(*ni), tvb_length_remaining(tvb, offset), "IPv4 node addresses");
643 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_node4);
644 p = offset + sizeof *ni;
645 for (i = 0; i < n; i++) {
646 tvb_memcpy(tvb, ipaddr, sizeof(gint32) + p, 4);
647 proto_tree_add_text(field_tree, tvb,
648 p, sizeof(guint32), "%s (TTL %d)", ip_to_str(ipaddr), tvb_get_ntohl(tvb, p));
649 p += sizeof(gint32) + sizeof(guint32);
651 off = tvb_length_remaining(tvb, offset);
657 /* the rest of data */
658 dissect_data(tvb_new_subset(tvb, offset + off, -1, -1), 0, pinfo, tree);
662 dissect_rrenum(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
664 proto_tree *field_tree, *opt_tree;
666 struct icmp6_router_renum icmp6_router_renum, *rr;
667 struct rr_pco_match rr_pco_match, *match;
668 struct rr_pco_use rr_pco_use, *use;
673 rr = &icmp6_router_renum;
674 tvb_memcpy(tvb, (guint8 *)rr, offset, sizeof *rr);
675 proto_tree_add_text(tree, tvb,
676 offset + offsetof(struct icmp6_router_renum, rr_seqnum), 4,
677 "Sequence number: 0x%08x", pntohl(&rr->rr_seqnum));
678 proto_tree_add_text(tree, tvb,
679 offset + offsetof(struct icmp6_router_renum, rr_segnum), 1,
680 "Segment number: 0x%02x", rr->rr_segnum);
682 flagoff = offset + offsetof(struct icmp6_router_renum, rr_flags);
683 flags = tvb_get_guint8(tvb, flagoff);
684 tf = proto_tree_add_text(tree, tvb, flagoff, 1,
685 "Flags: 0x%02x", flags);
686 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
687 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
688 decode_boolean_bitfield(flags, 0x80, 8,
689 "Test command", "Not test command"));
690 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
691 decode_boolean_bitfield(flags, 0x40, 8,
692 "Result requested", "Result not requested"));
693 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
694 decode_boolean_bitfield(flags, 0x20, 8,
695 "All interfaces", "Not all interfaces"));
696 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
697 decode_boolean_bitfield(flags, 0x10, 8,
698 "Site specific", "Not site specific"));
699 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
700 decode_boolean_bitfield(flags, 0x08, 8,
701 "Processed previously", "Complete result"));
703 proto_tree_add_text(tree, tvb,
704 offset + offsetof(struct icmp6_router_renum, rr_maxdelay), 2,
705 "Max delay: 0x%04x", pntohs(&rr->rr_maxdelay));
706 dissect_data(tvb_new_subset(tvb, offset + sizeof(*rr), -1, -1), 0, pinfo, tree); /*XXX*/
708 if (rr->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) {
709 off = offset + sizeof(*rr);
710 match = &rr_pco_match;
711 tvb_memcpy(tvb, (guint8 *)match, off, sizeof *match);
712 tf = proto_tree_add_text(tree, tvb, off, sizeof(*match),
713 "Match-Prefix: %s/%u (%u-%u)", ip6_to_str(&match->rpm_prefix),
714 match->rpm_matchlen, match->rpm_minlen, match->rpm_maxlen);
715 opt_tree = proto_item_add_subtree(tf, ett_icmpv6opt);
716 proto_tree_add_text(opt_tree, tvb,
717 off + offsetof(struct rr_pco_match, rpm_code),
718 sizeof(match->rpm_code), "OpCode: %s (%u)",
719 val_to_str(match->rpm_code, names_rrenum_matchcode, "Unknown"),
721 proto_tree_add_text(opt_tree, tvb,
722 off + offsetof(struct rr_pco_match, rpm_len),
723 sizeof(match->rpm_len), "OpLength: %u (%u octets)",
724 match->rpm_len, match->rpm_len * 8);
725 proto_tree_add_text(opt_tree, tvb,
726 off + offsetof(struct rr_pco_match, rpm_ordinal),
727 sizeof(match->rpm_ordinal), "Ordinal: %u", match->rpm_ordinal);
728 proto_tree_add_text(opt_tree, tvb,
729 off + offsetof(struct rr_pco_match, rpm_matchlen),
730 sizeof(match->rpm_matchlen), "MatchLen: %u", match->rpm_matchlen);
731 proto_tree_add_text(opt_tree, tvb,
732 off + offsetof(struct rr_pco_match, rpm_minlen),
733 sizeof(match->rpm_minlen), "MinLen: %u", match->rpm_minlen);
734 proto_tree_add_text(opt_tree, tvb,
735 off + offsetof(struct rr_pco_match, rpm_maxlen),
736 sizeof(match->rpm_maxlen), "MaxLen: %u", match->rpm_maxlen);
737 proto_tree_add_text(opt_tree, tvb,
738 off + offsetof(struct rr_pco_match, rpm_prefix),
739 sizeof(match->rpm_prefix), "MatchPrefix: %s",
740 ip6_to_str(&match->rpm_prefix));
742 off += sizeof(*match);
744 for (l = match->rpm_len * 8 - sizeof(*match);
745 l >= sizeof(*use); l -= sizeof(*use), off += sizeof(*use)) {
746 tvb_memcpy(tvb, (guint8 *)use, off, sizeof *use);
747 tf = proto_tree_add_text(tree, tvb, off, sizeof(*use),
748 "Use-Prefix: %s/%u (keep %u)", ip6_to_str(&use->rpu_prefix),
749 use->rpu_uselen, use->rpu_keeplen);
750 opt_tree = proto_item_add_subtree(tf, ett_icmpv6opt);
751 proto_tree_add_text(opt_tree, tvb,
752 off + offsetof(struct rr_pco_use, rpu_uselen),
753 sizeof(use->rpu_uselen), "UseLen: %u", use->rpu_uselen);
754 proto_tree_add_text(opt_tree, tvb,
755 off + offsetof(struct rr_pco_use, rpu_keeplen),
756 sizeof(use->rpu_keeplen), "KeepLen: %u", use->rpu_keeplen);
757 tf = proto_tree_add_text(opt_tree, tvb,
758 flagoff = off + offsetof(struct rr_pco_use, rpu_ramask),
759 sizeof(use->rpu_ramask), "FlagMask: 0x%x", use->rpu_ramask);
760 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
761 flags = tvb_get_guint8(tvb, flagoff);
762 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
763 decode_boolean_bitfield(flags,
764 ICMP6_RR_PCOUSE_RAFLAGS_ONLINK, 8,
765 "Onlink", "Not onlink"));
766 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
767 decode_boolean_bitfield(flags,
768 ICMP6_RR_PCOUSE_RAFLAGS_AUTO, 8,
769 "Auto", "Not auto"));
770 tf = proto_tree_add_text(opt_tree, tvb,
771 flagoff = off + offsetof(struct rr_pco_use, rpu_raflags),
772 sizeof(use->rpu_raflags), "RAFlags: 0x%x", use->rpu_raflags);
773 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
774 flags = tvb_get_guint8(tvb, flagoff);
775 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
776 decode_boolean_bitfield(flags,
777 ICMP6_RR_PCOUSE_RAFLAGS_ONLINK, 8,
778 "Onlink", "Not onlink"));
779 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
780 decode_boolean_bitfield(flags,
781 ICMP6_RR_PCOUSE_RAFLAGS_AUTO, 8, "Auto", "Not auto"));
782 if (pntohl(&use->rpu_vltime) == 0xffffffff)
783 proto_tree_add_text(opt_tree, tvb,
784 off + offsetof(struct rr_pco_use, rpu_vltime),
785 sizeof(use->rpu_vltime), "Valid Lifetime: infinity");
787 proto_tree_add_text(opt_tree, tvb,
788 off + offsetof(struct rr_pco_use, rpu_vltime),
789 sizeof(use->rpu_vltime), "Valid Lifetime: %u",
790 pntohl(&use->rpu_vltime));
791 if (pntohl(&use->rpu_pltime) == 0xffffffff)
792 proto_tree_add_text(opt_tree, tvb,
793 off + offsetof(struct rr_pco_use, rpu_pltime),
794 sizeof(use->rpu_pltime), "Preferred Lifetime: infinity");
796 proto_tree_add_text(opt_tree, tvb,
797 off + offsetof(struct rr_pco_use, rpu_pltime),
798 sizeof(use->rpu_pltime), "Preferred Lifetime: %u",
799 pntohl(&use->rpu_pltime));
800 tf = proto_tree_add_text(opt_tree, tvb,
801 flagoff = off + offsetof(struct rr_pco_use, rpu_flags),
802 sizeof(use->rpu_flags), "Flags: 0x%08x",
803 pntohl(&use->rpu_flags));
804 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
805 flags = tvb_get_guint8(tvb, flagoff);
806 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
807 decode_boolean_bitfield(flags,
808 ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, 32,
809 "Decrement valid lifetime", "No decrement valid lifetime"));
810 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
811 decode_boolean_bitfield(flags,
812 ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, 32,
813 "Decrement preferred lifetime",
814 "No decrement preferred lifetime"));
815 proto_tree_add_text(opt_tree, tvb,
816 off + offsetof(struct rr_pco_use, rpu_prefix),
817 sizeof(use->rpu_prefix), "UsePrefix: %s",
818 ip6_to_str(&use->rpu_prefix));
825 dissect_icmpv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
827 proto_tree *icmp6_tree, *field_tree;
828 proto_item *ti, *tf = NULL;
829 struct icmp6_hdr icmp6_hdr, *dp;
830 struct icmp6_nodeinfo *ni = NULL;
831 char *codename, *typename;
832 char *colcodename, *coltypename;
834 guint length, reported_length;
837 guint16 cksum, computed_cksum;
841 if (check_col(pinfo->fd, COL_PROTOCOL))
842 col_set_str(pinfo->fd, COL_PROTOCOL, "ICMPv6");
843 if (check_col(pinfo->fd, COL_INFO))
844 col_clear(pinfo->fd, COL_INFO);
847 tvb_memcpy(tvb, (guint8 *)&icmp6_hdr, offset, sizeof icmp6_hdr);
849 codename = typename = colcodename = coltypename = "Unknown";
851 switch (dp->icmp6_type) {
852 case ICMP6_DST_UNREACH:
853 typename = coltypename = "Unreachable";
854 switch (dp->icmp6_code) {
855 case ICMP6_DST_UNREACH_NOROUTE:
856 codename = colcodename = "Route unreachable";
858 case ICMP6_DST_UNREACH_ADMIN:
859 codename = colcodename = "Administratively prohibited";
861 case ICMP6_DST_UNREACH_NOTNEIGHBOR:
862 codename = colcodename = "Not a neighbor";
864 case ICMP6_DST_UNREACH_ADDR:
865 codename = colcodename = "Address unreachable";
867 case ICMP6_DST_UNREACH_NOPORT:
868 codename = colcodename = "Port unreachable";
872 case ICMP6_PACKET_TOO_BIG:
873 typename = coltypename = "Too big";
874 codename = colcodename = NULL;
876 case ICMP6_TIME_EXCEEDED:
877 typename = coltypename = "Time exceeded";
878 switch (dp->icmp6_code) {
879 case ICMP6_TIME_EXCEED_TRANSIT:
880 codename = colcodename = "In-transit";
882 case ICMP6_TIME_EXCEED_REASSEMBLY:
883 codename = colcodename = "Reassembly";
887 case ICMP6_PARAM_PROB:
888 typename = coltypename = "Parameter problem";
889 switch (dp->icmp6_code) {
890 case ICMP6_PARAMPROB_HEADER:
891 codename = colcodename = "Header";
893 case ICMP6_PARAMPROB_NEXTHEADER:
894 codename = colcodename = "Next header";
896 case ICMP6_PARAMPROB_OPTION:
897 codename = colcodename = "Option";
901 case ICMP6_ECHO_REQUEST:
902 typename = coltypename = "Echo request";
903 codename = colcodename = NULL;
905 case ICMP6_ECHO_REPLY:
906 typename = coltypename = "Echo reply";
907 codename = colcodename = NULL;
909 case ICMP6_MEMBERSHIP_QUERY:
910 typename = coltypename = "Multicast listener query";
911 codename = colcodename = NULL;
913 case ICMP6_MEMBERSHIP_REPORT:
914 typename = coltypename = "Multicast listener report";
915 codename = colcodename = NULL;
917 case ICMP6_MEMBERSHIP_REDUCTION:
918 typename = coltypename = "Multicast listener done";
919 codename = colcodename = NULL;
921 case ND_ROUTER_SOLICIT:
922 typename = coltypename = "Router solicitation";
923 codename = colcodename = NULL;
924 len = sizeof(struct nd_router_solicit);
926 case ND_ROUTER_ADVERT:
927 typename = coltypename = "Router advertisement";
928 codename = colcodename = NULL;
929 len = sizeof(struct nd_router_advert);
931 case ND_NEIGHBOR_SOLICIT:
932 typename = coltypename = "Neighbor solicitation";
933 codename = colcodename = NULL;
934 len = sizeof(struct nd_neighbor_solicit);
936 case ND_NEIGHBOR_ADVERT:
937 typename = coltypename = "Neighbor advertisement";
938 codename = colcodename = NULL;
939 len = sizeof(struct nd_neighbor_advert);
942 typename = coltypename = "Redirect";
943 codename = colcodename = NULL;
944 len = sizeof(struct nd_redirect);
946 case ICMP6_ROUTER_RENUMBERING:
947 typename = coltypename = "Router renumbering";
948 switch (dp->icmp6_code) {
949 case ICMP6_ROUTER_RENUMBERING_COMMAND:
950 codename = colcodename = "Command";
952 case ICMP6_ROUTER_RENUMBERING_RESULT:
953 codename = colcodename = "Result";
955 case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
956 codename = colcodename = "Sequence number reset";
959 len = sizeof(struct icmp6_router_renum);
963 ni = (struct icmp6_nodeinfo *)dp;
964 if (ni->ni_type == ICMP6_NI_QUERY) {
965 typename = coltypename = "Node information query";
966 switch (ni->ni_code) {
967 case ICMP6_NI_SUBJ_IPV6:
968 codename = "Query subject = IPv6 addresses";
970 case ICMP6_NI_SUBJ_FQDN:
971 if (tvb_bytes_exist(tvb, offset, sizeof(*ni)))
972 codename = "Query subject = DNS name";
974 codename = "Query subject = empty";
976 case ICMP6_NI_SUBJ_IPV4:
977 codename = "Query subject = IPv4 addresses";
981 typename = coltypename = "Node information reply";
982 switch (ni->ni_code) {
983 case ICMP6_NI_SUCCESS:
984 codename = "Successful";
986 case ICMP6_NI_REFUSED:
987 codename = "Refused";
989 case ICMP6_NI_UNKNOWN:
990 codename = "Unknown query type";
994 colcodename = val_to_str(pntohs(&ni->ni_qtype), names_nodeinfo_qtype,
996 len = sizeof(struct icmp6_nodeinfo);
1000 if (check_col(pinfo->fd, COL_INFO)) {
1001 char typebuf[256], codebuf[256];
1003 if (coltypename && strcmp(coltypename, "Unknown") == 0) {
1004 snprintf(typebuf, sizeof(typebuf), "Unknown (0x%02x)",
1006 coltypename = typebuf;
1008 if (colcodename && strcmp(colcodename, "Unknown") == 0) {
1009 snprintf(codebuf, sizeof(codebuf), "Unknown (0x%02x)",
1011 colcodename = codebuf;
1014 col_add_fstr(pinfo->fd, COL_INFO, "%s (%s)", coltypename, colcodename);
1016 col_add_fstr(pinfo->fd, COL_INFO, "%s", coltypename);
1021 /* !!! specify length */
1022 ti = proto_tree_add_item(tree, proto_icmpv6, tvb, offset, len, FALSE);
1023 icmp6_tree = proto_item_add_subtree(ti, ett_icmpv6);
1025 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_type, tvb,
1026 offset + offsetof(struct icmp6_hdr, icmp6_type), 1,
1028 "Type: %u (%s)", dp->icmp6_type, typename);
1030 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_code, tvb,
1031 offset + offsetof(struct icmp6_hdr, icmp6_code), 1,
1033 "Code: %u (%s)", dp->icmp6_code, codename);
1035 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_code, tvb,
1036 offset + offsetof(struct icmp6_hdr, icmp6_code), 1,
1038 "Code: %u", dp->icmp6_code);
1040 cksum = (guint16)htons(dp->icmp6_cksum);
1041 length = tvb_length(tvb);
1042 reported_length = tvb_reported_length(tvb);
1043 if (!pinfo->fragmented && length >= reported_length) {
1044 /* The packet isn't part of a fragmented datagram and isn't
1045 truncated, so we can checksum it. */
1047 /* Set up the fields of the pseudo-header. */
1048 cksum_vec[0].ptr = pinfo->src.data;
1049 cksum_vec[0].len = pinfo->src.len;
1050 cksum_vec[1].ptr = pinfo->dst.data;
1051 cksum_vec[1].len = pinfo->dst.len;
1052 cksum_vec[2].ptr = (const guint8 *)&phdr;
1053 phdr[0] = htonl(tvb_reported_length(tvb));
1054 phdr[1] = htonl(IP_PROTO_ICMPV6);
1055 cksum_vec[2].len = 8;
1056 cksum_vec[3].len = tvb_reported_length(tvb);
1057 cksum_vec[3].ptr = tvb_get_ptr(tvb, offset, cksum_vec[3].len);
1058 computed_cksum = in_cksum(cksum_vec, 4);
1059 if (computed_cksum == 0) {
1060 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_checksum,
1062 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1064 "Checksum: 0x%04x (correct)", cksum);
1066 proto_tree_add_boolean_hidden(icmp6_tree, hf_icmpv6_checksum_bad,
1068 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1070 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_checksum,
1072 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1074 "Checksum: 0x%04x (incorrect, should be 0x%04x)",
1075 cksum, in_cksum_shouldbe(cksum, computed_cksum));
1078 proto_tree_add_uint(icmp6_tree, hf_icmpv6_checksum, tvb,
1079 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1084 switch (dp->icmp6_type) {
1085 case ICMP6_DST_UNREACH:
1086 case ICMP6_TIME_EXCEEDED:
1087 dissect_contained_icmpv6(tvb, offset + sizeof(*dp), pinfo,
1090 case ICMP6_PACKET_TOO_BIG:
1091 proto_tree_add_text(icmp6_tree, tvb,
1092 offset + offsetof(struct icmp6_hdr, icmp6_mtu), 4,
1093 "MTU: %u", pntohl(&dp->icmp6_mtu));
1094 dissect_contained_icmpv6(tvb, offset + sizeof(*dp), pinfo,
1097 case ICMP6_PARAM_PROB:
1098 proto_tree_add_text(icmp6_tree, tvb,
1099 offset + offsetof(struct icmp6_hdr, icmp6_pptr), 4,
1100 "Problem pointer: 0x%04x", pntohl(&dp->icmp6_pptr));
1101 dissect_contained_icmpv6(tvb, offset + sizeof(*dp), pinfo,
1104 case ICMP6_ECHO_REQUEST:
1105 case ICMP6_ECHO_REPLY:
1106 proto_tree_add_text(icmp6_tree, tvb,
1107 offset + offsetof(struct icmp6_hdr, icmp6_id), 2,
1108 "ID: 0x%04x", (guint16)ntohs(dp->icmp6_id));
1109 proto_tree_add_text(icmp6_tree, tvb,
1110 offset + offsetof(struct icmp6_hdr, icmp6_seq), 2,
1111 "Sequence: 0x%04x", (guint16)ntohs(dp->icmp6_seq));
1112 next_tvb = tvb_new_subset(tvb, offset + sizeof(*dp), -1, -1);
1113 dissect_data(next_tvb, 0, pinfo, icmp6_tree);
1115 case ICMP6_MEMBERSHIP_QUERY:
1116 case ICMP6_MEMBERSHIP_REPORT:
1117 case ICMP6_MEMBERSHIP_REDUCTION:
1118 proto_tree_add_text(icmp6_tree, tvb,
1119 offset + offsetof(struct icmp6_hdr, icmp6_maxdelay), 2,
1120 "Maximum response delay: %u",
1121 (guint16)ntohs(dp->icmp6_maxdelay));
1122 proto_tree_add_text(icmp6_tree, tvb, offset + sizeof(*dp), 16,
1123 "Multicast Address: %s",
1124 ip6_to_str((struct e_in6_addr *)(tvb_get_ptr(tvb, offset + sizeof *dp, sizeof (struct e_in6_addr)))));
1126 case ND_ROUTER_SOLICIT:
1127 dissect_icmpv6opt(tvb, offset + sizeof(*dp), pinfo, icmp6_tree);
1129 case ND_ROUTER_ADVERT:
1131 struct nd_router_advert nd_router_advert, *ra;
1135 ra = &nd_router_advert;
1136 tvb_memcpy(tvb, (guint8 *)ra, offset, sizeof *ra);
1137 proto_tree_add_text(icmp6_tree, tvb,
1138 offset + offsetof(struct nd_router_advert, nd_ra_curhoplimit),
1139 1, "Cur hop limit: %u", ra->nd_ra_curhoplimit);
1141 flagoff = offset + offsetof(struct nd_router_advert, nd_ra_flags_reserved);
1142 ra_flags = tvb_get_guint8(tvb, flagoff);
1143 tf = proto_tree_add_text(icmp6_tree, tvb, flagoff, 1, "Flags: 0x%02x", ra_flags);
1144 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1145 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1146 decode_boolean_bitfield(ra_flags,
1147 0x80, 8, "Managed", "Not managed"));
1148 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1149 decode_boolean_bitfield(ra_flags,
1150 0x40, 8, "Other", "Not other"));
1151 /* BT INSERT BEGIN */
1152 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1153 decode_boolean_bitfield(ra_flags,
1154 0x20, 8, "Home Agent", "Not Home Agent"));
1156 proto_tree_add_text(icmp6_tree, tvb,
1157 offset + offsetof(struct nd_router_advert, nd_ra_router_lifetime),
1158 2, "Router lifetime: %u",
1159 (guint16)ntohs(ra->nd_ra_router_lifetime));
1160 proto_tree_add_text(icmp6_tree, tvb,
1161 offset + offsetof(struct nd_router_advert, nd_ra_reachable), 4,
1162 "Reachable time: %u", pntohl(&ra->nd_ra_reachable));
1163 proto_tree_add_text(icmp6_tree, tvb,
1164 offset + offsetof(struct nd_router_advert, nd_ra_retransmit), 4,
1165 "Retrans time: %u", pntohl(&ra->nd_ra_retransmit));
1166 dissect_icmpv6opt(tvb, offset + sizeof(struct nd_router_advert), pinfo, icmp6_tree);
1169 case ND_NEIGHBOR_SOLICIT:
1171 struct nd_neighbor_solicit nd_neighbor_solicit, *ns;
1173 ns = &nd_neighbor_solicit;
1174 tvb_memcpy(tvb, (guint8 *)ns, offset, sizeof *ns);
1175 proto_tree_add_text(icmp6_tree, tvb,
1176 offset + offsetof(struct nd_neighbor_solicit, nd_ns_target), 16,
1179 get_hostname6(&ns->nd_ns_target),
1183 ip6_to_str(&ns->nd_ns_target));
1185 dissect_icmpv6opt(tvb, offset + sizeof(*ns), pinfo, icmp6_tree);
1188 case ND_NEIGHBOR_ADVERT:
1190 int flagoff, targetoff;
1192 struct e_in6_addr na_target;
1194 flagoff = offset + offsetof(struct nd_neighbor_advert, nd_na_flags_reserved);
1195 na_flags = tvb_get_ntohl(tvb, flagoff);
1197 tf = proto_tree_add_text(icmp6_tree, tvb, flagoff, 4, "Flags: 0x%08x", na_flags);
1198 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1199 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
1200 decode_boolean_bitfield(na_flags,
1201 ND_NA_FLAG_ROUTER, 32, "Router", "Not router"));
1202 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
1203 decode_boolean_bitfield(na_flags,
1204 ND_NA_FLAG_SOLICITED, 32, "Solicited", "Not adverted"));
1205 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
1206 decode_boolean_bitfield(na_flags,
1207 ND_NA_FLAG_OVERRIDE, 32, "Override", "Not override"));
1209 targetoff = offset + offsetof(struct nd_neighbor_advert, nd_na_target);
1210 tvb_memcpy(tvb, (guint8 *)&na_target, targetoff, sizeof na_target);
1211 proto_tree_add_text(icmp6_tree, tvb, targetoff, 16,
1214 get_hostname6(&na_target),
1218 ip6_to_str(&na_target));
1220 dissect_icmpv6opt(tvb, offset + sizeof(struct nd_neighbor_advert), pinfo, icmp6_tree);
1225 struct nd_redirect nd_redirect, *rd;
1228 tvb_memcpy(tvb, (guint8 *)rd, offset, sizeof *rd);
1229 proto_tree_add_text(icmp6_tree, tvb,
1230 offset + offsetof(struct nd_redirect, nd_rd_target), 16,
1233 get_hostname6(&rd->nd_rd_target),
1237 ip6_to_str(&rd->nd_rd_target));
1239 proto_tree_add_text(icmp6_tree, tvb,
1240 offset + offsetof(struct nd_redirect, nd_rd_dst), 16,
1242 "Destination: %s (%s)",
1243 get_hostname6(&rd->nd_rd_dst),
1247 ip6_to_str(&rd->nd_rd_dst));
1249 dissect_icmpv6opt(tvb, offset + sizeof(*rd), pinfo, icmp6_tree);
1252 case ICMP6_ROUTER_RENUMBERING:
1253 dissect_rrenum(tvb, offset, pinfo, icmp6_tree);
1255 case ICMP6_NI_QUERY:
1256 case ICMP6_NI_REPLY:
1257 ni = (struct icmp6_nodeinfo *)dp;
1258 proto_tree_add_text(icmp6_tree, tvb,
1259 offset + offsetof(struct icmp6_nodeinfo, ni_qtype),
1260 sizeof(ni->ni_qtype),
1261 "Query type: 0x%04x (%s)", pntohs(&ni->ni_qtype),
1262 val_to_str(pntohs(&ni->ni_qtype), names_nodeinfo_qtype,
1264 dissect_nodeinfo(tvb, offset, pinfo, icmp6_tree);
1267 next_tvb = tvb_new_subset(tvb, offset + sizeof(*dp), -1, -1);
1268 dissect_data(next_tvb, 0, pinfo, tree);
1275 proto_register_icmpv6(void)
1277 static hf_register_info hf[] = {
1279 { "Type", "icmpv6.type", FT_UINT8, BASE_DEC, NULL, 0x0,
1282 { "Code", "icmpv6.code", FT_UINT8, BASE_DEC, NULL, 0x0,
1284 { &hf_icmpv6_checksum,
1285 { "Checksum", "icmpv6.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
1287 { &hf_icmpv6_checksum_bad,
1288 { "Bad Checksum", "icmpv6.checksum_bad", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1291 static gint *ett[] = {
1296 &ett_nodeinfo_subject4,
1297 &ett_nodeinfo_subject6,
1298 &ett_nodeinfo_node4,
1299 &ett_nodeinfo_node6,
1300 &ett_nodeinfo_nodebitmap,
1301 &ett_nodeinfo_nodedns,
1304 proto_icmpv6 = proto_register_protocol("Internet Control Message Protocol v6",
1305 "ICMPv6", "icmpv6");
1306 proto_register_field_array(proto_icmpv6, hf, array_length(hf));
1307 proto_register_subtree_array(ett, array_length(ett));
1311 proto_reg_handoff_icmpv6(void)
1313 dissector_add("ip.proto", IP_PROTO_ICMPV6, dissect_icmpv6, proto_icmpv6);
1316 * Get a handle for the IPv6 dissector.
1318 ipv6_handle = find_dissector("ipv6");