2 * Routines for ICMPv6 packet disassembly
4 * $Id: packet-icmpv6.c,v 1.40 2001/04/23 03:56:57 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-ip.h"
57 #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;
370 char dname[MAXDNAME];
373 int top_level_offset;
375 ni = &icmp6_nodeinfo;
376 tvb_memcpy(tvb, (guint8 *)ni, offset, sizeof *ni);
378 flags = pntohs(&ni->ni_flags);
379 tf = proto_tree_add_text(tree, tvb,
380 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
381 sizeof(ni->ni_flags), "Flags: 0x%04x", flags);
382 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_flag);
383 switch (pntohs(&ni->ni_qtype)) {
384 case NI_QTYPE_SUPTYPES:
385 if (ni->ni_type == ICMP6_NI_QUERY) {
386 proto_tree_add_text(field_tree, tvb,
387 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
388 sizeof(ni->ni_flags), "%s",
389 decode_boolean_bitfield(flags, NI_SUPTYPE_FLAG_COMPRESS, sizeof(flags) * 8,
390 "Compressed reply supported",
391 "No compressed reply support"));
393 proto_tree_add_text(field_tree, tvb,
394 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
395 sizeof(ni->ni_flags), "%s",
396 decode_boolean_bitfield(flags, NI_SUPTYPE_FLAG_COMPRESS, sizeof(flags) * 8,
397 "Compressed", "Not compressed"));
400 case NI_QTYPE_DNSNAME:
401 if (ni->ni_type == ICMP6_NI_REPLY) {
402 proto_tree_add_text(field_tree, tvb,
403 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
404 sizeof(ni->ni_flags), "%s",
405 decode_boolean_bitfield(flags, NI_FQDN_FLAG_VALIDTTL, sizeof(flags) * 8,
406 "Valid TTL field", "Meaningless TTL field"));
409 case NI_QTYPE_NODEADDR:
410 proto_tree_add_text(field_tree, tvb,
411 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
412 sizeof(ni->ni_flags), "%s",
413 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_GLOBAL, sizeof(flags) * 8,
415 "Not global address"));
416 proto_tree_add_text(field_tree, tvb,
417 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
418 sizeof(ni->ni_flags), "%s",
419 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_SITELOCAL, sizeof(flags) * 8,
420 "Site-local address",
421 "Not site-local address"));
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_NODEADDR_FLAG_LINKLOCAL, sizeof(flags) * 8,
426 "Link-local address",
427 "Not link-local address"));
428 proto_tree_add_text(field_tree, tvb,
429 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
430 sizeof(ni->ni_flags), "%s",
431 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_COMPAT, sizeof(flags) * 8,
432 "IPv4 compatible/mapped address",
433 "Not IPv4 compatible/mapped address"));
435 case NI_QTYPE_IPV4ADDR:
436 proto_tree_add_text(field_tree, tvb,
437 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
438 sizeof(ni->ni_flags), "%s",
439 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_ALL, sizeof(flags) * 8,
440 "All unicast address",
441 "Unicast addresses on the queried interface"));
442 proto_tree_add_text(field_tree, tvb,
443 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
444 sizeof(ni->ni_flags), "%s",
445 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_TRUNCATE, sizeof(flags) * 8,
446 "Truncated", "Not truncated"));
451 proto_tree_add_text(tree, tvb,
452 offset + offsetof(struct icmp6_nodeinfo, icmp6_ni_nonce[0]),
453 sizeof(ni->icmp6_ni_nonce), "Nonce: 0x%08x%08x",
454 pntohl(&ni->icmp6_ni_nonce[0]), pntohl(&ni->icmp6_ni_nonce[4]));
456 /* offset for "the rest of data" */
460 if (!tvb_bytes_exist(tvb, offset, sizeof(*ni)))
462 if (ni->ni_type == ICMP6_NI_QUERY) {
463 switch (ni->ni_code) {
464 case ICMP6_NI_SUBJ_IPV6:
465 n = tvb_length_remaining(tvb, offset + sizeof(*ni));
466 n /= sizeof(struct e_in6_addr);
467 tf = proto_tree_add_text(tree, tvb,
468 offset + sizeof(*ni), tvb_length_remaining(tvb, offset), "IPv6 subject addresses");
469 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_subject6);
470 p = offset + sizeof *ni;
471 for (i = 0; i < n; i++) {
472 struct e_in6_addr e_in6_addr;
473 tvb_memcpy(tvb, (guint8 *)&e_in6_addr, p, sizeof e_in6_addr);
474 proto_tree_add_text(field_tree, tvb,
475 p, sizeof(struct e_in6_addr),
476 "%s", ip6_to_str(&e_in6_addr));
477 p += sizeof(struct e_in6_addr);
479 off = tvb_length_remaining(tvb, offset);
481 case ICMP6_NI_SUBJ_FQDN:
482 /* XXXX - clean this up when packet-dns.c has been tvbuffified */
483 tvb_compat(tvb, &pd, &top_level_offset);
484 l = get_dns_name(pd, top_level_offset + offset + sizeof(*ni),
485 top_level_offset + offset + sizeof(*ni),
486 dname, sizeof(dname));
487 if (tvb_bytes_exist(tvb, offset + sizeof(*ni) + l, 1) &&
488 tvb_get_guint8(tvb, offset + sizeof(*ni) + l) == 0) {
490 proto_tree_add_text(tree, tvb, offset + sizeof(*ni), l,
491 "DNS label: %s (truncated)", dname);
493 proto_tree_add_text(tree, tvb, offset + sizeof(*ni), l,
494 "DNS label: %s", dname);
496 off = tvb_length_remaining(tvb, offset + sizeof(*ni) + l);
498 case ICMP6_NI_SUBJ_IPV4:
499 n = tvb_length_remaining(tvb, offset + sizeof(*ni));
500 n /= sizeof(guint32);
501 tf = proto_tree_add_text(tree, tvb,
502 offset + sizeof(*ni), tvb_length_remaining(tvb, offset), "IPv4 subject addresses");
503 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_subject4);
504 p = offset + sizeof *ni;
505 for (i = 0; i < n; i++) {
506 tvb_memcpy(tvb, ipaddr, p, 4);
507 proto_tree_add_text(field_tree, tvb,
508 p, sizeof(guint32), "%s", ip_to_str(ipaddr));
509 p += sizeof(guint32);
511 off = tvb_length_remaining(tvb, offset);
515 switch (pntohs(&ni->ni_qtype)) {
518 case NI_QTYPE_SUPTYPES:
519 p = offset + sizeof *ni;
520 tf = proto_tree_add_text(tree, tvb,
521 offset + sizeof(*ni), tvb_length_remaining(tvb, p),
522 "Supported type bitmap%s",
523 (flags & 0x0001) ? ", compressed" : "");
524 field_tree = proto_item_add_subtree(tf,
525 ett_nodeinfo_nodebitmap);
527 while (tvb_bytes_exist(tvb, p, sizeof(guint32))) { /* XXXX Check what? */
528 if ((flags & 0x0001) == 0) {
529 l = tvb_length_remaining(tvb, offset + sizeof(*ni));
530 l /= sizeof(guint32);
533 l = tvb_get_ntohs(tvb, p);
534 i = tvb_get_ntohs(tvb, p + sizeof(guint16)); /*skip*/
536 if (n + l * 32 > (1 << 16))
538 if (n + (l + i) * 32 > (1 << 16))
540 if ((flags & 0x0001) == 0) {
541 proto_tree_add_text(field_tree, tvb, p,
542 l * 4, "Bitmap (%d to %d): %s", n, n + l * 32 - 1,
543 bitrange(tvb, p, l, n));
546 proto_tree_add_text(field_tree, tvb, p,
547 4 + l * 4, "Bitmap (%d to %d): %s", n, n + l * 32 - 1,
548 bitrange(tvb, p + 4, l, n));
551 n += l * 32 + i * 32;
553 off = tvb_length_remaining(tvb, offset);
555 case NI_QTYPE_DNSNAME:
556 proto_tree_add_text(tree, tvb, offset + sizeof(*ni),
557 sizeof(gint32), "TTL: %d", (gint32)tvb_get_ntohl(tvb, offset + sizeof *ni));
558 tf = proto_tree_add_text(tree, tvb,
559 offset + sizeof(*ni) + sizeof(guint32),
560 tvb_length_remaining(tvb, offset),
562 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_nodedns);
563 /* XXXX - clean this up when packet-dns.c has been tvbuffified */
564 tvb_compat(tvb, &pd, &top_level_offset);
565 i = offset + sizeof (*ni) + sizeof(guint32);
566 while (i < tvb_length(tvb)) {
567 l = get_dns_name(pd, top_level_offset + i,
568 top_level_offset + offset + sizeof (*ni) + sizeof(guint32),
569 dname,sizeof(dname));
570 if (tvb_bytes_exist(tvb, top_level_offset + i + l, 1) &&
571 tvb_get_guint8(tvb, top_level_offset + i + l) == 0) {
573 proto_tree_add_text(field_tree, tvb, i, l,
574 "DNS label: %s (truncated)", dname);
576 proto_tree_add_text(field_tree, tvb, i, l,
577 "DNS label: %s", dname);
581 off = tvb_length_remaining(tvb, offset);
583 case NI_QTYPE_NODEADDR:
584 n = tvb_length_remaining(tvb, offset + sizeof(*ni));
585 n /= sizeof(gint32) + sizeof(struct e_in6_addr);
586 tf = proto_tree_add_text(tree, tvb,
587 offset + sizeof(*ni), tvb_length_remaining(tvb, offset), "IPv6 node addresses");
588 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_node6);
589 p = offset + sizeof (*ni);
590 for (i = 0; i < n; i++) {
591 struct e_in6_addr e_in6_addr;
593 ttl = (gint32)tvb_get_ntohl(tvb, p);
594 tvb_memcpy(tvb, (guint8 *)&e_in6_addr, p + sizeof ttl, sizeof e_in6_addr);
595 proto_tree_add_text(field_tree, tvb,
596 p, sizeof(struct e_in6_addr) + sizeof(gint32),
597 "%s (TTL %d)", ip6_to_str(&e_in6_addr), ttl);
598 p += sizeof(struct e_in6_addr) + sizeof(gint32);
600 off = tvb_length_remaining(tvb, offset);
602 case NI_QTYPE_IPV4ADDR:
603 n = tvb_length_remaining(tvb, offset + sizeof(*ni));
604 n /= sizeof(gint32) + sizeof(guint32);
605 tf = proto_tree_add_text(tree, tvb,
606 offset + sizeof(*ni), tvb_length_remaining(tvb, offset), "IPv4 node addresses");
607 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_node4);
608 p = offset + sizeof *ni;
609 for (i = 0; i < n; i++) {
610 tvb_memcpy(tvb, ipaddr, sizeof(gint32) + p, 4);
611 proto_tree_add_text(field_tree, tvb,
612 p, sizeof(guint32), "%s (TTL %d)", ip_to_str(ipaddr), tvb_get_ntohl(tvb, p));
613 p += sizeof(gint32) + sizeof(guint32);
615 off = tvb_length_remaining(tvb, offset);
621 /* the rest of data */
622 dissect_data(tvb_new_subset(tvb, offset + off, -1, -1), 0, pinfo, tree);
626 dissect_rrenum(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
628 proto_tree *field_tree, *opt_tree;
630 struct icmp6_router_renum icmp6_router_renum, *rr;
631 struct rr_pco_match rr_pco_match, *match;
632 struct rr_pco_use rr_pco_use, *use;
636 rr = &icmp6_router_renum;
637 tvb_memcpy(tvb, (guint8 *)rr, offset, sizeof *rr);
638 proto_tree_add_text(tree, tvb,
639 offset + offsetof(struct icmp6_router_renum, rr_seqnum), 4,
640 "Sequence number: 0x%08x", pntohl(&rr->rr_seqnum));
641 proto_tree_add_text(tree, tvb,
642 offset + offsetof(struct icmp6_router_renum, rr_segnum), 1,
643 "Segment number: 0x%02x", rr->rr_segnum);
645 flagoff = offset + offsetof(struct icmp6_router_renum, rr_flags);
646 flags = tvb_get_guint8(tvb, flagoff);
647 tf = proto_tree_add_text(tree, tvb, flagoff, 1,
648 "Flags: 0x%02x", flags);
649 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
650 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
651 decode_boolean_bitfield(flags, 0x80, 8,
652 "Test command", "Not test command"));
653 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
654 decode_boolean_bitfield(flags, 0x40, 8,
655 "Result requested", "Result not requested"));
656 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
657 decode_boolean_bitfield(flags, 0x20, 8,
658 "All interfaces", "Not all interfaces"));
659 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
660 decode_boolean_bitfield(flags, 0x10, 8,
661 "Site specific", "Not site specific"));
662 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
663 decode_boolean_bitfield(flags, 0x08, 8,
664 "Processed previously", "Complete result"));
666 proto_tree_add_text(tree, tvb,
667 offset + offsetof(struct icmp6_router_renum, rr_maxdelay), 2,
668 "Max delay: 0x%04x", pntohs(&rr->rr_maxdelay));
669 dissect_data(tvb_new_subset(tvb, offset + sizeof(*rr), -1, -1), 0, pinfo, tree); /*XXX*/
671 if (rr->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) {
672 off = offset + sizeof(*rr);
673 match = &rr_pco_match;
674 tvb_memcpy(tvb, (guint8 *)match, off, sizeof *match);
675 tf = proto_tree_add_text(tree, tvb, off, sizeof(*match),
676 "Match-Prefix: %s/%u (%u-%u)", ip6_to_str(&match->rpm_prefix),
677 match->rpm_matchlen, match->rpm_minlen, match->rpm_maxlen);
678 opt_tree = proto_item_add_subtree(tf, ett_icmpv6opt);
679 proto_tree_add_text(opt_tree, tvb,
680 off + offsetof(struct rr_pco_match, rpm_code),
681 sizeof(match->rpm_code), "OpCode: %s (%u)",
682 val_to_str(match->rpm_code, names_rrenum_matchcode, "Unknown"),
684 proto_tree_add_text(opt_tree, tvb,
685 off + offsetof(struct rr_pco_match, rpm_len),
686 sizeof(match->rpm_len), "OpLength: %u (%u octets)",
687 match->rpm_len, match->rpm_len * 8);
688 proto_tree_add_text(opt_tree, tvb,
689 off + offsetof(struct rr_pco_match, rpm_ordinal),
690 sizeof(match->rpm_ordinal), "Ordinal: %u", match->rpm_ordinal);
691 proto_tree_add_text(opt_tree, tvb,
692 off + offsetof(struct rr_pco_match, rpm_matchlen),
693 sizeof(match->rpm_matchlen), "MatchLen: %u", match->rpm_matchlen);
694 proto_tree_add_text(opt_tree, tvb,
695 off + offsetof(struct rr_pco_match, rpm_minlen),
696 sizeof(match->rpm_minlen), "MinLen: %u", match->rpm_minlen);
697 proto_tree_add_text(opt_tree, tvb,
698 off + offsetof(struct rr_pco_match, rpm_maxlen),
699 sizeof(match->rpm_maxlen), "MaxLen: %u", match->rpm_maxlen);
700 proto_tree_add_text(opt_tree, tvb,
701 off + offsetof(struct rr_pco_match, rpm_prefix),
702 sizeof(match->rpm_prefix), "MatchPrefix: %s",
703 ip6_to_str(&match->rpm_prefix));
705 off += sizeof(*match);
707 for (l = match->rpm_len * 8 - sizeof(*match);
708 l >= sizeof(*use); l -= sizeof(*use), off += sizeof(*use)) {
709 tvb_memcpy(tvb, (guint8 *)use, off, sizeof *use);
710 tf = proto_tree_add_text(tree, tvb, off, sizeof(*use),
711 "Use-Prefix: %s/%u (keep %u)", ip6_to_str(&use->rpu_prefix),
712 use->rpu_uselen, use->rpu_keeplen);
713 opt_tree = proto_item_add_subtree(tf, ett_icmpv6opt);
714 proto_tree_add_text(opt_tree, tvb,
715 off + offsetof(struct rr_pco_use, rpu_uselen),
716 sizeof(use->rpu_uselen), "UseLen: %u", use->rpu_uselen);
717 proto_tree_add_text(opt_tree, tvb,
718 off + offsetof(struct rr_pco_use, rpu_keeplen),
719 sizeof(use->rpu_keeplen), "KeepLen: %u", use->rpu_keeplen);
720 tf = proto_tree_add_text(opt_tree, tvb,
721 flagoff = off + offsetof(struct rr_pco_use, rpu_ramask),
722 sizeof(use->rpu_ramask), "FlagMask: 0x%x", use->rpu_ramask);
723 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
724 flags = tvb_get_guint8(tvb, flagoff);
725 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
726 decode_boolean_bitfield(flags,
727 ICMP6_RR_PCOUSE_RAFLAGS_ONLINK, 8,
728 "Onlink", "Not onlink"));
729 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
730 decode_boolean_bitfield(flags,
731 ICMP6_RR_PCOUSE_RAFLAGS_AUTO, 8,
732 "Auto", "Not auto"));
733 tf = proto_tree_add_text(opt_tree, tvb,
734 flagoff = off + offsetof(struct rr_pco_use, rpu_raflags),
735 sizeof(use->rpu_raflags), "RAFlags: 0x%x", use->rpu_raflags);
736 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
737 flags = tvb_get_guint8(tvb, flagoff);
738 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
739 decode_boolean_bitfield(flags,
740 ICMP6_RR_PCOUSE_RAFLAGS_ONLINK, 8,
741 "Onlink", "Not onlink"));
742 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
743 decode_boolean_bitfield(flags,
744 ICMP6_RR_PCOUSE_RAFLAGS_AUTO, 8, "Auto", "Not auto"));
745 if (pntohl(&use->rpu_vltime) == 0xffffffff)
746 proto_tree_add_text(opt_tree, tvb,
747 off + offsetof(struct rr_pco_use, rpu_vltime),
748 sizeof(use->rpu_vltime), "Valid Lifetime: infinity");
750 proto_tree_add_text(opt_tree, tvb,
751 off + offsetof(struct rr_pco_use, rpu_vltime),
752 sizeof(use->rpu_vltime), "Valid Lifetime: %u",
753 pntohl(&use->rpu_vltime));
754 if (pntohl(&use->rpu_pltime) == 0xffffffff)
755 proto_tree_add_text(opt_tree, tvb,
756 off + offsetof(struct rr_pco_use, rpu_pltime),
757 sizeof(use->rpu_pltime), "Preferred Lifetime: infinity");
759 proto_tree_add_text(opt_tree, tvb,
760 off + offsetof(struct rr_pco_use, rpu_pltime),
761 sizeof(use->rpu_pltime), "Preferred Lifetime: %u",
762 pntohl(&use->rpu_pltime));
763 tf = proto_tree_add_text(opt_tree, tvb,
764 flagoff = off + offsetof(struct rr_pco_use, rpu_flags),
765 sizeof(use->rpu_flags), "Flags: 0x%08x",
766 pntohl(&use->rpu_flags));
767 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
768 flags = tvb_get_guint8(tvb, flagoff);
769 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
770 decode_boolean_bitfield(flags,
771 ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, 32,
772 "Decrement valid lifetime", "No decrement valid lifetime"));
773 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
774 decode_boolean_bitfield(flags,
775 ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, 32,
776 "Decrement preferred lifetime",
777 "No decrement preferred lifetime"));
778 proto_tree_add_text(opt_tree, tvb,
779 off + offsetof(struct rr_pco_use, rpu_prefix),
780 sizeof(use->rpu_prefix), "UsePrefix: %s",
781 ip6_to_str(&use->rpu_prefix));
788 dissect_icmpv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
790 proto_tree *icmp6_tree, *field_tree;
791 proto_item *ti, *tf = NULL;
792 struct icmp6_hdr icmp6_hdr, *dp;
793 struct icmp6_nodeinfo *ni = NULL;
794 char *codename, *typename;
795 char *colcodename, *coltypename;
797 guint length, reported_length;
800 guint16 cksum, computed_cksum;
805 tvb_memcpy(tvb, (guint8 *)&icmp6_hdr, offset, sizeof icmp6_hdr);
807 codename = typename = colcodename = coltypename = "Unknown";
809 switch (dp->icmp6_type) {
810 case ICMP6_DST_UNREACH:
811 typename = coltypename = "Unreachable";
812 switch (dp->icmp6_code) {
813 case ICMP6_DST_UNREACH_NOROUTE:
814 codename = colcodename = "Route unreachable";
816 case ICMP6_DST_UNREACH_ADMIN:
817 codename = colcodename = "Administratively prohibited";
819 case ICMP6_DST_UNREACH_NOTNEIGHBOR:
820 codename = colcodename = "Not a neighbor";
822 case ICMP6_DST_UNREACH_ADDR:
823 codename = colcodename = "Address unreachable";
825 case ICMP6_DST_UNREACH_NOPORT:
826 codename = colcodename = "Port unreachable";
830 case ICMP6_PACKET_TOO_BIG:
831 typename = coltypename = "Too big";
832 codename = colcodename = NULL;
834 case ICMP6_TIME_EXCEEDED:
835 typename = coltypename = "Time exceeded";
836 switch (dp->icmp6_code) {
837 case ICMP6_TIME_EXCEED_TRANSIT:
838 codename = colcodename = "In-transit";
840 case ICMP6_TIME_EXCEED_REASSEMBLY:
841 codename = colcodename = "Reassembly";
845 case ICMP6_PARAM_PROB:
846 typename = coltypename = "Parameter problem";
847 switch (dp->icmp6_code) {
848 case ICMP6_PARAMPROB_HEADER:
849 codename = colcodename = "Header";
851 case ICMP6_PARAMPROB_NEXTHEADER:
852 codename = colcodename = "Next header";
854 case ICMP6_PARAMPROB_OPTION:
855 codename = colcodename = "Option";
859 case ICMP6_ECHO_REQUEST:
860 typename = coltypename = "Echo request";
861 codename = colcodename = NULL;
863 case ICMP6_ECHO_REPLY:
864 typename = coltypename = "Echo reply";
865 codename = colcodename = NULL;
867 case ICMP6_MEMBERSHIP_QUERY:
868 typename = coltypename = "Multicast listener query";
869 codename = colcodename = NULL;
871 case ICMP6_MEMBERSHIP_REPORT:
872 typename = coltypename = "Multicast listener report";
873 codename = colcodename = NULL;
875 case ICMP6_MEMBERSHIP_REDUCTION:
876 typename = coltypename = "Multicast listener done";
877 codename = colcodename = NULL;
879 case ND_ROUTER_SOLICIT:
880 typename = coltypename = "Router solicitation";
881 codename = colcodename = NULL;
882 len = sizeof(struct nd_router_solicit);
884 case ND_ROUTER_ADVERT:
885 typename = coltypename = "Router advertisement";
886 codename = colcodename = NULL;
887 len = sizeof(struct nd_router_advert);
889 case ND_NEIGHBOR_SOLICIT:
890 typename = coltypename = "Neighbor solicitation";
891 codename = colcodename = NULL;
892 len = sizeof(struct nd_neighbor_solicit);
894 case ND_NEIGHBOR_ADVERT:
895 typename = coltypename = "Neighbor advertisement";
896 codename = colcodename = NULL;
897 len = sizeof(struct nd_neighbor_advert);
900 typename = coltypename = "Redirect";
901 codename = colcodename = NULL;
902 len = sizeof(struct nd_redirect);
904 case ICMP6_ROUTER_RENUMBERING:
905 typename = coltypename = "Router renumbering";
906 switch (dp->icmp6_code) {
907 case ICMP6_ROUTER_RENUMBERING_COMMAND:
908 codename = colcodename = "Command";
910 case ICMP6_ROUTER_RENUMBERING_RESULT:
911 codename = colcodename = "Result";
913 case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
914 codename = colcodename = "Sequence number reset";
917 len = sizeof(struct icmp6_router_renum);
921 ni = (struct icmp6_nodeinfo *)dp;
922 if (ni->ni_type == ICMP6_NI_QUERY) {
923 typename = coltypename = "Node information query";
924 switch (ni->ni_code) {
925 case ICMP6_NI_SUBJ_IPV6:
926 codename = "Query subject = IPv6 addresses";
928 case ICMP6_NI_SUBJ_FQDN:
929 if (tvb_bytes_exist(tvb, offset, sizeof(*ni)))
930 codename = "Query subject = DNS name";
932 codename = "Query subject = empty";
934 case ICMP6_NI_SUBJ_IPV4:
935 codename = "Query subject = IPv4 addresses";
939 typename = coltypename = "Node information reply";
940 switch (ni->ni_code) {
941 case ICMP6_NI_SUCCESS:
942 codename = "Successful";
944 case ICMP6_NI_REFUSED:
945 codename = "Refused";
947 case ICMP6_NI_UNKNOWN:
948 codename = "Unknown query type";
952 colcodename = val_to_str(pntohs(&ni->ni_qtype), names_nodeinfo_qtype,
954 len = sizeof(struct icmp6_nodeinfo);
958 if (check_col(pinfo->fd, COL_PROTOCOL))
959 col_set_str(pinfo->fd, COL_PROTOCOL, "ICMPv6");
960 if (check_col(pinfo->fd, COL_INFO)) {
961 char typebuf[256], codebuf[256];
963 if (coltypename && strcmp(coltypename, "Unknown") == 0) {
964 snprintf(typebuf, sizeof(typebuf), "Unknown (0x%02x)",
966 coltypename = typebuf;
968 if (colcodename && strcmp(colcodename, "Unknown") == 0) {
969 snprintf(codebuf, sizeof(codebuf), "Unknown (0x%02x)",
971 colcodename = codebuf;
974 col_add_fstr(pinfo->fd, COL_INFO, "%s (%s)", coltypename, colcodename);
976 col_add_fstr(pinfo->fd, COL_INFO, "%s", coltypename);
981 /* !!! specify length */
982 ti = proto_tree_add_item(tree, proto_icmpv6, tvb, offset, len, FALSE);
983 icmp6_tree = proto_item_add_subtree(ti, ett_icmpv6);
985 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_type, tvb,
986 offset + offsetof(struct icmp6_hdr, icmp6_type), 1,
988 "Type: %u (%s)", dp->icmp6_type, typename);
990 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_code, tvb,
991 offset + offsetof(struct icmp6_hdr, icmp6_code), 1,
993 "Code: %u (%s)", dp->icmp6_code, codename);
995 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_code, tvb,
996 offset + offsetof(struct icmp6_hdr, icmp6_code), 1,
998 "Code: %u", dp->icmp6_code);
1000 cksum = (guint16)htons(dp->icmp6_cksum);
1001 length = tvb_length(tvb);
1002 reported_length = tvb_reported_length(tvb);
1003 if (!pinfo->fragmented && length >= reported_length) {
1004 /* The packet isn't part of a fragmented datagram and isn't
1005 truncated, so we can checksum it. */
1007 /* Set up the fields of the pseudo-header. */
1008 cksum_vec[0].ptr = pinfo->src.data;
1009 cksum_vec[0].len = pinfo->src.len;
1010 cksum_vec[1].ptr = pinfo->dst.data;
1011 cksum_vec[1].len = pinfo->dst.len;
1012 cksum_vec[2].ptr = (const guint8 *)&phdr;
1013 phdr[0] = htonl(tvb_reported_length(tvb));
1014 phdr[1] = htonl(IP_PROTO_ICMPV6);
1015 cksum_vec[2].len = 8;
1016 cksum_vec[3].len = tvb_reported_length(tvb);
1017 cksum_vec[3].ptr = tvb_get_ptr(tvb, offset, cksum_vec[3].len);
1018 computed_cksum = in_cksum(cksum_vec, 4);
1019 if (computed_cksum == 0) {
1020 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_checksum,
1022 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1024 "Checksum: 0x%04x (correct)", cksum);
1026 proto_tree_add_boolean_hidden(icmp6_tree, hf_icmpv6_checksum_bad,
1028 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1030 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_checksum,
1032 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1034 "Checksum: 0x%04x (incorrect, should be 0x%04x)",
1035 cksum, in_cksum_shouldbe(cksum, computed_cksum));
1038 proto_tree_add_uint(icmp6_tree, hf_icmpv6_checksum, tvb,
1039 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1044 next_tvb = tvb_new_subset(tvb, offset + sizeof(*dp), -1, -1);
1045 switch (dp->icmp6_type) {
1046 case ICMP6_DST_UNREACH:
1047 case ICMP6_TIME_EXCEEDED:
1048 /* tiny sanity check */
1049 if ((tvb_get_guint8(tvb, offset + sizeof(*dp)) & 0xf0) == 0x60) {
1050 /* The invoking packet is an IPv6 datagram; dissect it.
1052 Set the columns non-writable, so that the packet list
1053 shows this as an ICMPv6 packet, not as the type of packet
1054 for which the ICMPv6 packet was generated. */
1055 col_set_writable(pinfo->fd, FALSE);
1057 call_dissector(ipv6_handle, next_tvb, pinfo, icmp6_tree);
1059 dissect_data(next_tvb, 0, pinfo, icmp6_tree);
1062 case ICMP6_PACKET_TOO_BIG:
1063 proto_tree_add_text(icmp6_tree, tvb,
1064 offset + offsetof(struct icmp6_hdr, icmp6_mtu), 4,
1065 "MTU: %u", pntohl(&dp->icmp6_mtu));
1066 /* tiny sanity check */
1067 if ((tvb_get_guint8(tvb, offset + sizeof(*dp)) & 0xf0) == 0x60) {
1068 /* The invoking packet is an IPv6 datagram; dissect it.
1070 Set the columns non-writable, so that the packet list
1071 shows this as an ICMPv6 packet, not as the type of packet
1072 for which the ICMPv6 packet was generated. */
1073 col_set_writable(pinfo->fd, FALSE);
1075 call_dissector(ipv6_handle, next_tvb, pinfo, icmp6_tree);
1077 dissect_data(next_tvb, 0, pinfo, icmp6_tree);
1080 case ICMP6_PARAM_PROB:
1081 proto_tree_add_text(icmp6_tree, tvb,
1082 offset + offsetof(struct icmp6_hdr, icmp6_pptr), 4,
1083 "Problem pointer: 0x%04x", pntohl(&dp->icmp6_pptr));
1084 /* tiny sanity check */
1085 if ((tvb_get_guint8(tvb, offset + sizeof(*dp)) & 0xf0) == 0x60) {
1086 /* The invoking packet is an IPv6 datagram; dissect it.
1088 Set the columns non-writable, so that the packet list
1089 shows this as an ICMPv6 packet, not as the type of packet
1090 for which the ICMPv6 packet was generated. */
1091 col_set_writable(pinfo->fd, FALSE);
1093 call_dissector(ipv6_handle, next_tvb, pinfo, icmp6_tree);
1095 dissect_data(next_tvb, 0, pinfo, icmp6_tree);
1098 case ICMP6_ECHO_REQUEST:
1099 case ICMP6_ECHO_REPLY:
1100 proto_tree_add_text(icmp6_tree, tvb,
1101 offset + offsetof(struct icmp6_hdr, icmp6_id), 2,
1102 "ID: 0x%04x", (guint16)ntohs(dp->icmp6_id));
1103 proto_tree_add_text(icmp6_tree, tvb,
1104 offset + offsetof(struct icmp6_hdr, icmp6_seq), 2,
1105 "Sequence: 0x%04x", (guint16)ntohs(dp->icmp6_seq));
1106 dissect_data(next_tvb, 0, pinfo, icmp6_tree);
1108 case ICMP6_MEMBERSHIP_QUERY:
1109 case ICMP6_MEMBERSHIP_REPORT:
1110 case ICMP6_MEMBERSHIP_REDUCTION:
1111 proto_tree_add_text(icmp6_tree, tvb,
1112 offset + offsetof(struct icmp6_hdr, icmp6_maxdelay), 2,
1113 "Maximum response delay: %u",
1114 (guint16)ntohs(dp->icmp6_maxdelay));
1115 proto_tree_add_text(icmp6_tree, tvb, offset + sizeof(*dp), 16,
1116 "Multicast Address: %s",
1117 ip6_to_str((struct e_in6_addr *)(tvb_get_ptr(tvb, offset + sizeof *dp, sizeof (struct e_in6_addr)))));
1119 case ND_ROUTER_SOLICIT:
1120 dissect_icmpv6opt(tvb, offset + sizeof(*dp), pinfo, icmp6_tree);
1122 case ND_ROUTER_ADVERT:
1124 struct nd_router_advert nd_router_advert, *ra;
1128 ra = &nd_router_advert;
1129 tvb_memcpy(tvb, (guint8 *)ra, offset, sizeof *ra);
1130 proto_tree_add_text(icmp6_tree, tvb,
1131 offset + offsetof(struct nd_router_advert, nd_ra_curhoplimit),
1132 1, "Cur hop limit: %u", ra->nd_ra_curhoplimit);
1134 flagoff = offset + offsetof(struct nd_router_advert, nd_ra_flags_reserved);
1135 ra_flags = tvb_get_guint8(tvb, flagoff);
1136 tf = proto_tree_add_text(icmp6_tree, tvb, flagoff, 1, "Flags: 0x%02x", ra_flags);
1137 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1138 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1139 decode_boolean_bitfield(ra_flags,
1140 0x80, 8, "Managed", "Not managed"));
1141 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1142 decode_boolean_bitfield(ra_flags,
1143 0x40, 8, "Other", "Not other"));
1144 /* BT INSERT BEGIN */
1145 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1146 decode_boolean_bitfield(ra_flags,
1147 0x20, 8, "Home Agent", "Not Home Agent"));
1149 proto_tree_add_text(icmp6_tree, tvb,
1150 offset + offsetof(struct nd_router_advert, nd_ra_router_lifetime),
1151 2, "Router lifetime: %u",
1152 (guint16)ntohs(ra->nd_ra_router_lifetime));
1153 proto_tree_add_text(icmp6_tree, tvb,
1154 offset + offsetof(struct nd_router_advert, nd_ra_reachable), 4,
1155 "Reachable time: %u", pntohl(&ra->nd_ra_reachable));
1156 proto_tree_add_text(icmp6_tree, tvb,
1157 offset + offsetof(struct nd_router_advert, nd_ra_retransmit), 4,
1158 "Retrans time: %u", pntohl(&ra->nd_ra_retransmit));
1159 dissect_icmpv6opt(tvb, offset + sizeof(struct nd_router_advert), pinfo, icmp6_tree);
1162 case ND_NEIGHBOR_SOLICIT:
1164 struct nd_neighbor_solicit nd_neighbor_solicit, *ns;
1166 ns = &nd_neighbor_solicit;
1167 tvb_memcpy(tvb, (guint8 *)ns, offset, sizeof *ns);
1168 proto_tree_add_text(icmp6_tree, tvb,
1169 offset + offsetof(struct nd_neighbor_solicit, nd_ns_target), 16,
1172 get_hostname6(&ns->nd_ns_target),
1176 ip6_to_str(&ns->nd_ns_target));
1178 dissect_icmpv6opt(tvb, offset + sizeof(*ns), pinfo, icmp6_tree);
1181 case ND_NEIGHBOR_ADVERT:
1183 int flagoff, targetoff;
1185 struct e_in6_addr na_target;
1187 flagoff = offset + offsetof(struct nd_neighbor_advert, nd_na_flags_reserved);
1188 na_flags = tvb_get_ntohl(tvb, flagoff);
1190 tf = proto_tree_add_text(icmp6_tree, tvb, flagoff, 4, "Flags: 0x%08x", na_flags);
1191 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1192 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
1193 decode_boolean_bitfield(na_flags,
1194 ND_NA_FLAG_ROUTER, 32, "Router", "Not router"));
1195 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
1196 decode_boolean_bitfield(na_flags,
1197 ND_NA_FLAG_SOLICITED, 32, "Solicited", "Not adverted"));
1198 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
1199 decode_boolean_bitfield(na_flags,
1200 ND_NA_FLAG_OVERRIDE, 32, "Override", "Not override"));
1202 targetoff = offset + offsetof(struct nd_neighbor_advert, nd_na_target);
1203 tvb_memcpy(tvb, (guint8 *)&na_target, targetoff, sizeof na_target);
1204 proto_tree_add_text(icmp6_tree, tvb, targetoff, 16,
1207 get_hostname6(&na_target),
1211 ip6_to_str(&na_target));
1213 dissect_icmpv6opt(tvb, offset + sizeof(struct nd_neighbor_advert), pinfo, icmp6_tree);
1218 struct nd_redirect nd_redirect, *rd;
1221 tvb_memcpy(tvb, (guint8 *)rd, offset, sizeof *rd);
1222 proto_tree_add_text(icmp6_tree, tvb,
1223 offset + offsetof(struct nd_redirect, nd_rd_target), 16,
1226 get_hostname6(&rd->nd_rd_target),
1230 ip6_to_str(&rd->nd_rd_target));
1232 proto_tree_add_text(icmp6_tree, tvb,
1233 offset + offsetof(struct nd_redirect, nd_rd_dst), 16,
1235 "Destination: %s (%s)",
1236 get_hostname6(&rd->nd_rd_dst),
1240 ip6_to_str(&rd->nd_rd_dst));
1242 dissect_icmpv6opt(tvb, offset + sizeof(*rd), pinfo, icmp6_tree);
1245 case ICMP6_ROUTER_RENUMBERING:
1246 dissect_rrenum(tvb, offset, pinfo, icmp6_tree);
1248 case ICMP6_NI_QUERY:
1249 case ICMP6_NI_REPLY:
1250 ni = (struct icmp6_nodeinfo *)dp;
1251 proto_tree_add_text(icmp6_tree, tvb,
1252 offset + offsetof(struct icmp6_nodeinfo, ni_qtype),
1253 sizeof(ni->ni_qtype),
1254 "Query type: 0x%04x (%s)", pntohs(&ni->ni_qtype),
1255 val_to_str(pntohs(&ni->ni_qtype), names_nodeinfo_qtype,
1257 dissect_nodeinfo(tvb, offset, pinfo, icmp6_tree);
1260 dissect_data(next_tvb, 0, pinfo, tree);
1267 proto_register_icmpv6(void)
1269 static hf_register_info hf[] = {
1271 { "Type", "icmpv6.type", FT_UINT8, BASE_DEC, NULL, 0x0,
1274 { "Code", "icmpv6.code", FT_UINT8, BASE_DEC, NULL, 0x0,
1276 { &hf_icmpv6_checksum,
1277 { "Checksum", "icmpv6.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
1279 { &hf_icmpv6_checksum_bad,
1280 { "Bad Checksum", "icmpv6.checksum_bad", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1283 static gint *ett[] = {
1288 &ett_nodeinfo_subject4,
1289 &ett_nodeinfo_subject6,
1290 &ett_nodeinfo_node4,
1291 &ett_nodeinfo_node6,
1292 &ett_nodeinfo_nodebitmap,
1293 &ett_nodeinfo_nodedns,
1296 proto_icmpv6 = proto_register_protocol("Internet Control Message Protocol v6",
1297 "ICMPv6", "icmpv6");
1298 proto_register_field_array(proto_icmpv6, hf, array_length(hf));
1299 proto_register_subtree_array(ett, array_length(ett));
1303 proto_reg_handoff_icmpv6(void)
1305 dissector_add("ip.proto", IP_PROTO_ICMPV6, dissect_icmpv6, proto_icmpv6);
1308 * Get a handle for the IPv6 dissector.
1310 ipv6_handle = find_dissector("ipv6");