2 * Routines for ICMPv6 packet disassembly
4 * $Id: packet-icmpv6.c,v 1.30 2000/11/11 10:23:41 guy Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@zing.org>
8 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
39 #ifdef HAVE_SYS_TYPES_H
40 # include <sys/types.h>
43 #ifdef HAVE_NETINET_IN_H
44 # include <netinet/in.h>
49 #ifdef NEED_SNPRINTF_H
50 # include "snprintf.h"
54 #include "packet-ipv6.h"
55 #include "packet-ip.h"
56 #include "packet-dns.h"
60 #define offsetof(type, member) ((size_t)(&((type *)0)->member))
63 static int proto_icmpv6 = -1;
64 static int hf_icmpv6_type = -1;
65 static int hf_icmpv6_code = -1;
66 static int hf_icmpv6_checksum = -1;
68 static gint ett_icmpv6 = -1;
69 static gint ett_icmpv6opt = -1;
70 static gint ett_icmpv6flag = -1;
71 static gint ett_nodeinfo_flag = -1;
72 static gint ett_nodeinfo_subject4 = -1;
73 static gint ett_nodeinfo_subject6 = -1;
74 static gint ett_nodeinfo_node4 = -1;
75 static gint ett_nodeinfo_node6 = -1;
76 static gint ett_nodeinfo_nodebitmap = -1;
77 static gint ett_nodeinfo_nodedns = -1;
79 static const value_string names_nodeinfo_qtype[] = {
80 { NI_QTYPE_NOOP, "NOOP" },
81 { NI_QTYPE_SUPTYPES, "Supported query types" },
82 { NI_QTYPE_DNSNAME, "DNS name" },
83 { NI_QTYPE_NODEADDR, "Node addresses" },
84 { NI_QTYPE_IPV4ADDR, "IPv4 node addresses" },
88 static const value_string names_rrenum_matchcode[] = {
89 { RPM_PCO_ADD, "Add" },
90 { RPM_PCO_CHANGE, "Change" },
91 { RPM_PCO_SETGLOBAL, "Set Global" },
96 dissect_icmpv6opt(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
98 proto_tree *icmp6opt_tree, *field_tree;
100 struct nd_opt_hdr *opt;
108 if (!IS_DATA_IN_FRAME(offset))
111 opt = (struct nd_opt_hdr *)&pd[offset];
112 len = opt->nd_opt_len << 3;
114 /* !!! specify length */
115 ti = proto_tree_add_text(tree, NullTVB, offset, len, "ICMPv6 options");
116 icmp6opt_tree = proto_item_add_subtree(ti, ett_icmpv6opt);
118 switch (opt->nd_opt_type) {
119 case ND_OPT_SOURCE_LINKADDR:
120 typename = "Source link-layer address";
122 case ND_OPT_TARGET_LINKADDR:
123 typename = "Target link-layer address";
125 case ND_OPT_PREFIX_INFORMATION:
126 typename = "Prefix information";
128 case ND_OPT_REDIRECTED_HEADER:
129 typename = "Redirected header";
135 typename = "Unknown";
139 proto_tree_add_text(icmp6opt_tree, NullTVB,
140 offset + offsetof(struct nd_opt_hdr, nd_opt_type), 1,
141 "Type: 0x%02x (%s)", opt->nd_opt_type, typename);
142 proto_tree_add_text(icmp6opt_tree, NullTVB,
143 offset + offsetof(struct nd_opt_hdr, nd_opt_len), 1,
144 "Length: %d bytes (0x%02x)", opt->nd_opt_len << 3, opt->nd_opt_len);
147 switch (opt->nd_opt_type) {
148 case ND_OPT_SOURCE_LINKADDR:
149 case ND_OPT_TARGET_LINKADDR:
154 len = (opt->nd_opt_len << 3) - sizeof(*opt);
155 t = (char *)malloc(len * 3);
156 memset(t, 0, len * 3);
157 p = &pd[offset + sizeof(*opt)];
158 for (i = 0; i < len; i++) {
161 sprintf(&t[i * 3], "%02x", p[i] & 0xff);
163 proto_tree_add_text(icmp6opt_tree, NullTVB,
164 offset + sizeof(*opt), len, "Link-layer address: %s", t);
167 case ND_OPT_PREFIX_INFORMATION:
169 struct nd_opt_prefix_info *pi = (struct nd_opt_prefix_info *)opt;
171 proto_tree_add_text(icmp6opt_tree, NullTVB,
172 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_prefix_len),
173 1, "Prefix length: %d", pi->nd_opt_pi_prefix_len);
175 flagoff = offsetof(struct nd_opt_prefix_info, nd_opt_pi_flags_reserved);
176 tf = proto_tree_add_text(icmp6opt_tree, NullTVB, flagoff, 1, "Flags: 0x%02x",
177 pntohl(&pi->nd_opt_pi_flags_reserved));
178 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
179 proto_tree_add_text(field_tree, NullTVB, flagoff, 1, "%s",
180 decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
181 0x80, 8, "Onlink", "Not onlink"));
182 proto_tree_add_text(field_tree, NullTVB, flagoff, 1, "%s",
183 decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
184 0x40, 8, "Auto", "Not auto"));
186 proto_tree_add_text(icmp6opt_tree, NullTVB,
187 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_valid_time),
188 4, "Valid lifetime: 0x%08x",
189 pntohl(&pi->nd_opt_pi_valid_time));
190 proto_tree_add_text(icmp6opt_tree, NullTVB,
191 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_preferred_time),
192 4, "Preferred lifetime: 0x%08x",
193 pntohl(&pi->nd_opt_pi_preferred_time));
194 proto_tree_add_text(icmp6opt_tree, NullTVB,
195 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_prefix),
196 16, "Prefix: %s", ip6_to_str(&pi->nd_opt_pi_prefix));
199 case ND_OPT_REDIRECTED_HEADER:
200 proto_tree_add_text(icmp6opt_tree, NullTVB,
201 offset + 8, (opt->nd_opt_len << 3) - 8, "Redirected packet");
202 /* tiny sanity check */
203 if ((pd[offset + 8] & 0xf0) == 0x60)
204 dissect_ipv6(pd, offset + 8, fd, icmp6opt_tree);
206 old_dissect_data(pd, offset + 8, fd, icmp6opt_tree);
210 struct nd_opt_mtu *pi = (struct nd_opt_mtu *)opt;
211 proto_tree_add_text(icmp6opt_tree, NullTVB,
212 offset + offsetof(struct nd_opt_mtu, nd_opt_mtu_mtu), 4,
213 "MTU: %d", pntohl(&pi->nd_opt_mtu_mtu));
218 if (opt->nd_opt_len == 0) {
219 proto_tree_add_text(icmp6opt_tree, NullTVB,
220 offset + offsetof(struct nd_opt_hdr, nd_opt_len), 1,
221 "Invalid option length: %d",
226 offset += (opt->nd_opt_len << 3);
231 * draft-ietf-ipngwg-icmp-name-lookups-06.txt
232 * Note that the packet format was changed several times in the past.
236 bitrange0(v, s, buf, buflen)
256 ep = buf + buflen - 1;
257 memset(buf, 0, buflen);
260 /* shift till we have 0x01 */
261 if ((v & 0x01) == 0) {
264 v >>= 4; off += 4; continue;
266 v >>= 3; off += 3; continue;
267 case 0x04: case 0x0c:
268 v >>= 2; off += 2; continue;
270 v >>= 1; off += 1; continue;
274 /* we have 0x01 with us */
275 for (i = 0; i < 32 - off; i++) {
276 if ((v & (0x01 << i)) == 0)
280 l = snprintf(p, ep - p, ",%d", s + off);
282 l = snprintf(p, ep - p, ",%d-%d", s + off,
296 bitrange(u_char *p, int l, int s)
298 static char buf[1024];
302 memset(buf, 0, sizeof(buf));
304 eq = buf + sizeof(buf) - 1;
305 for (i = 0; i < l; i++) {
306 if (bitrange0(pntohl(p + i * 4), s + i * 4, q, eq - q) == NULL) {
307 if (q != buf && q + 5 < buf + sizeof(buf))
308 strncpy(q, ",...", 5);
317 dissect_nodeinfo(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
319 proto_tree *field_tree;
321 struct icmp6_nodeinfo *ni;
326 char dname[MAXDNAME];
328 ni = (struct icmp6_nodeinfo *)&pd[offset];
331 flags = pntohs(&ni->ni_flags);
332 tf = proto_tree_add_text(tree, NullTVB,
333 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
334 sizeof(ni->ni_flags), "Flags: 0x%04x", flags);
335 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_flag);
336 switch (pntohs(&ni->ni_qtype)) {
337 case NI_QTYPE_SUPTYPES:
338 if (ni->ni_type == ICMP6_NI_QUERY) {
339 proto_tree_add_text(field_tree, NullTVB,
340 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
341 sizeof(ni->ni_flags), "%s",
342 decode_boolean_bitfield(flags, NI_SUPTYPE_FLAG_COMPRESS, sizeof(flags) * 8,
343 "Compressed reply supported",
344 "No compressed reply support"));
346 proto_tree_add_text(field_tree, NullTVB,
347 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
348 sizeof(ni->ni_flags), "%s",
349 decode_boolean_bitfield(flags, NI_SUPTYPE_FLAG_COMPRESS, sizeof(flags) * 8,
350 "Compressed", "Not compressed"));
353 case NI_QTYPE_DNSNAME:
354 if (ni->ni_type == ICMP6_NI_REPLY) {
355 proto_tree_add_text(field_tree, NullTVB,
356 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
357 sizeof(ni->ni_flags), "%s",
358 decode_boolean_bitfield(flags, NI_FQDN_FLAG_VALIDTTL, sizeof(flags) * 8,
359 "Valid TTL field", "Meaningless TTL field"));
362 case NI_QTYPE_NODEADDR:
363 proto_tree_add_text(field_tree, NullTVB,
364 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
365 sizeof(ni->ni_flags), "%s",
366 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_GLOBAL, sizeof(flags) * 8,
368 "Not global address"));
369 proto_tree_add_text(field_tree, NullTVB,
370 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
371 sizeof(ni->ni_flags), "%s",
372 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_SITELOCAL, sizeof(flags) * 8,
373 "Site-local address",
374 "Not site-local address"));
375 proto_tree_add_text(field_tree, NullTVB,
376 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
377 sizeof(ni->ni_flags), "%s",
378 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_LINKLOCAL, sizeof(flags) * 8,
379 "Link-local address",
380 "Not link-local address"));
381 proto_tree_add_text(field_tree, NullTVB,
382 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
383 sizeof(ni->ni_flags), "%s",
384 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_COMPAT, sizeof(flags) * 8,
385 "IPv4 compatible/mapped address",
386 "Not IPv4 compatible/mapped address"));
388 case NI_QTYPE_IPV4ADDR:
389 proto_tree_add_text(field_tree, NullTVB,
390 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
391 sizeof(ni->ni_flags), "%s",
392 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_ALL, sizeof(flags) * 8,
393 "All unicast address",
394 "Unicast addresses on the queried interface"));
395 proto_tree_add_text(field_tree, NullTVB,
396 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
397 sizeof(ni->ni_flags), "%s",
398 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_TRUNCATE, sizeof(flags) * 8,
399 "Truncated", "Not truncated"));
404 proto_tree_add_text(tree, NullTVB,
405 offset + offsetof(struct icmp6_nodeinfo, icmp6_ni_nonce[0]),
406 sizeof(ni->icmp6_ni_nonce), "Nonce: 0x%08x%08x",
407 pntohl(&ni->icmp6_ni_nonce[0]), pntohl(&ni->icmp6_ni_nonce[4]));
409 /* offset for "the rest of data" */
413 if (!IS_DATA_IN_FRAME(offset + sizeof(*ni)))
415 if (ni->ni_type == ICMP6_NI_QUERY) {
416 switch (ni->ni_code) {
417 case ICMP6_NI_SUBJ_IPV6:
418 n = pi.captured_len - (offset + sizeof(*ni));
419 n /= sizeof(struct e_in6_addr);
420 tf = proto_tree_add_text(tree, NullTVB,
421 offset + sizeof(*ni), END_OF_FRAME, "IPv6 subject addresses");
422 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_subject6);
423 p = (u_char *)(ni + 1);
424 for (i = 0; i < n; i++) {
425 proto_tree_add_text(field_tree, NullTVB,
426 p - pd, sizeof(struct e_in6_addr),
427 "%s", ip6_to_str((struct e_in6_addr *)p));
428 p += sizeof(struct e_in6_addr);
430 off = pi.captured_len - offset;
432 case ICMP6_NI_SUBJ_FQDN:
433 l = get_dns_name(pd, offset + sizeof(*ni), offset + sizeof(*ni),
434 dname, sizeof(dname));
435 if (IS_DATA_IN_FRAME(offset + sizeof(*ni) + l) &&
436 pd[offset + sizeof(*ni) + l] == 0) {
438 proto_tree_add_text(tree, NullTVB, offset + sizeof(*ni), l,
439 "DNS label: %s (truncated)", dname);
441 proto_tree_add_text(tree, NullTVB, offset + sizeof(*ni), l,
442 "DNS label: %s", dname);
444 off = offset + sizeof(*ni) + l;
446 case ICMP6_NI_SUBJ_IPV4:
447 n = pi.captured_len - (offset + sizeof(*ni));
448 n /= sizeof(guint32);
449 tf = proto_tree_add_text(tree, NullTVB,
450 offset + sizeof(*ni), END_OF_FRAME, "IPv4 subject addresses");
451 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_subject4);
452 p = (u_char *)(ni + 1);
453 for (i = 0; i < n; i++) {
454 proto_tree_add_text(field_tree, NullTVB,
455 p - pd, sizeof(guint32), "%s", ip_to_str(p));
456 p += sizeof(guint32);
458 off = pi.captured_len - offset;
462 switch (pntohs(&ni->ni_qtype)) {
465 case NI_QTYPE_SUPTYPES:
466 p = (u_char *)(ni + 1);
467 tf = proto_tree_add_text(tree, NullTVB,
468 offset + sizeof(*ni), END_OF_FRAME,
469 "Supported type bitmap%s",
470 (flags & 0x0001) ? ", compressed" : "");
471 field_tree = proto_item_add_subtree(tf,
472 ett_nodeinfo_nodebitmap);
474 while (IS_DATA_IN_FRAME(p - pd)) {
475 if ((flags & 0x0001) == 0) {
476 l = pi.captured_len - (offset + sizeof(*ni));
477 l /= sizeof(guint32);
480 if (!IS_DATA_IN_FRAME(p + sizeof(guint32) - 1 - pd))
483 i = pntohs(p + sizeof(guint16)); /*skip*/
485 if (n + l * 32 > (1 << 16))
487 if (n + (l + i) * 32 > (1 << 16))
489 if ((flags & 0x0001) == 0) {
490 proto_tree_add_text(field_tree, NullTVB, p - pd,
491 l * 4, "Bitmap (%d to %d): %s", n, n + l * 32 - 1,
495 proto_tree_add_text(field_tree, NullTVB, p - pd,
496 4 + l * 4, "Bitmap (%d to %d): %s", n, n + l * 32 - 1,
497 bitrange(p + 4, l, n));
500 n += l * 32 + i * 32;
502 off = pi.captured_len - offset;
504 case NI_QTYPE_DNSNAME:
505 proto_tree_add_text(tree, NullTVB, offset + sizeof(*ni),
506 sizeof(gint32), "TTL: %d", (gint32)pntohl(ni + 1));
507 tf = proto_tree_add_text(tree, NullTVB,
508 offset + sizeof(*ni) + sizeof(guint32), END_OF_FRAME,
510 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_nodedns);
512 i = offset + sizeof(*ni) + sizeof(guint32);
513 while (i < pi.captured_len) {
514 l = get_dns_name(pd, i, offset + sizeof(*ni), dname,
516 if (IS_DATA_IN_FRAME(i + l) && pd[i + l] == 0) {
518 proto_tree_add_text(field_tree, NullTVB, i, l,
519 "DNS label: %s (truncated)", dname);
521 proto_tree_add_text(field_tree, NullTVB, i, l,
522 "DNS label: %s", dname);
526 off = pi.captured_len - offset;
528 case NI_QTYPE_NODEADDR:
529 n = pi.captured_len - (offset + sizeof(*ni));
530 n /= sizeof(struct e_in6_addr) + sizeof(gint32);;
531 tf = proto_tree_add_text(tree, NullTVB,
532 offset + sizeof(*ni), END_OF_FRAME, "IPv6 node addresses");
533 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_node6);
534 p = (u_char *)(ni + 1);
535 for (i = 0; i < n; i++) {
536 proto_tree_add_text(field_tree, NullTVB,
537 p - pd, sizeof(struct e_in6_addr) + sizeof(gint32),
538 "%s (TTL %d)", ip6_to_str((struct e_in6_addr *)p),
539 (gint32)pntohl(p + sizeof(struct e_in6_addr)));
540 p += sizeof(struct e_in6_addr) + sizeof(gint32);
542 off = pi.captured_len - offset;
544 case NI_QTYPE_IPV4ADDR:
545 n = pi.captured_len - (offset + sizeof(*ni));
546 n /= sizeof(guint32);
547 tf = proto_tree_add_text(tree, NullTVB,
548 offset + sizeof(*ni), END_OF_FRAME, "IPv4 node addresses");
549 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_node4);
550 p = (u_char *)(ni + 1);
551 for (i = 0; i < n; i++) {
552 proto_tree_add_text(field_tree, NullTVB,
553 p - pd, sizeof(guint32), "%s", ip_to_str(p));
554 p += sizeof(guint32);
556 off = pi.captured_len - offset;
562 /* the rest of data */
563 old_dissect_data(pd, offset + off, fd, tree);
567 dissect_rrenum(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
569 proto_tree *field_tree, *opt_tree;
571 struct icmp6_router_renum *rr = (struct icmp6_router_renum *)&pd[offset];
572 struct rr_pco_match *match;
573 struct rr_pco_use *use;
576 proto_tree_add_text(tree, NullTVB,
577 offset + offsetof(struct icmp6_router_renum, rr_seqnum), 4,
578 "Sequence number: 0x%08x", pntohl(&rr->rr_seqnum));
579 proto_tree_add_text(tree, NullTVB,
580 offset + offsetof(struct icmp6_router_renum, rr_segnum), 1,
581 "Segment number: 0x%02x", rr->rr_segnum);
583 flagoff = offset + offsetof(struct icmp6_router_renum, rr_flags);
584 tf = proto_tree_add_text(tree, NullTVB, flagoff, 1,
585 "Flags: 0x%02x", pd[flagoff]);
586 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
587 proto_tree_add_text(field_tree, NullTVB, flagoff, 1, "%s",
588 decode_boolean_bitfield(pd[flagoff], 0x80, 8,
589 "Test command", "Not test command"));
590 proto_tree_add_text(field_tree, NullTVB, flagoff, 1, "%s",
591 decode_boolean_bitfield(pd[flagoff], 0x40, 8,
592 "Result requested", "Result not requested"));
593 proto_tree_add_text(field_tree, NullTVB, flagoff, 1, "%s",
594 decode_boolean_bitfield(pd[flagoff], 0x20, 8,
595 "All interfaces", "Not all interfaces"));
596 proto_tree_add_text(field_tree, NullTVB, flagoff, 1, "%s",
597 decode_boolean_bitfield(pd[flagoff], 0x10, 8,
598 "Site specific", "Not site specific"));
599 proto_tree_add_text(field_tree, NullTVB, flagoff, 1, "%s",
600 decode_boolean_bitfield(pd[flagoff], 0x08, 8,
601 "Processed previously", "Complete result"));
603 proto_tree_add_text(tree, NullTVB,
604 offset + offsetof(struct icmp6_router_renum, rr_maxdelay), 2,
605 "Max delay: 0x%04x", pntohs(&rr->rr_maxdelay));
606 old_dissect_data(pd, offset + sizeof(*rr), fd, tree); /*XXX*/
608 if (rr->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) {
609 off = offset + sizeof(*rr);
610 match = (struct rr_pco_match *)&pd[off];
611 tf = proto_tree_add_text(tree, NullTVB, off, sizeof(*match),
612 "Match-Prefix: %s/%u (%u-%u)", ip6_to_str(&match->rpm_prefix),
613 match->rpm_matchlen, match->rpm_minlen, match->rpm_maxlen);
614 opt_tree = proto_item_add_subtree(tf, ett_icmpv6opt);
615 proto_tree_add_text(opt_tree, NullTVB,
616 off + offsetof(struct rr_pco_match, rpm_code),
617 sizeof(match->rpm_code), "OpCode: %s (%u)",
618 val_to_str(match->rpm_code, names_rrenum_matchcode, "Unknown"),
620 proto_tree_add_text(opt_tree, NullTVB,
621 off + offsetof(struct rr_pco_match, rpm_len),
622 sizeof(match->rpm_len), "OpLength: %u (%u octets)",
623 match->rpm_len, match->rpm_len * 8);
624 proto_tree_add_text(opt_tree, NullTVB,
625 off + offsetof(struct rr_pco_match, rpm_ordinal),
626 sizeof(match->rpm_ordinal), "Ordinal: %u", match->rpm_ordinal);
627 proto_tree_add_text(opt_tree, NullTVB,
628 off + offsetof(struct rr_pco_match, rpm_matchlen),
629 sizeof(match->rpm_matchlen), "MatchLen: %u", match->rpm_matchlen);
630 proto_tree_add_text(opt_tree, NullTVB,
631 off + offsetof(struct rr_pco_match, rpm_minlen),
632 sizeof(match->rpm_minlen), "MinLen: %u", match->rpm_minlen);
633 proto_tree_add_text(opt_tree, NullTVB,
634 off + offsetof(struct rr_pco_match, rpm_maxlen),
635 sizeof(match->rpm_maxlen), "MaxLen: %u", match->rpm_maxlen);
636 proto_tree_add_text(opt_tree, NullTVB,
637 off + offsetof(struct rr_pco_match, rpm_prefix),
638 sizeof(match->rpm_prefix), "MatchPrefix: %s",
639 ip6_to_str(&match->rpm_prefix));
641 off += sizeof(*match);
642 use = (struct rr_pco_use *)&pd[off];
643 for (l = match->rpm_len * 8 - sizeof(*match);
644 l >= sizeof(*use); l -= sizeof(*use), off += sizeof(*use)) {
645 tf = proto_tree_add_text(tree, NullTVB, off, sizeof(*use),
646 "Use-Prefix: %s/%u (keep %u)", ip6_to_str(&use->rpu_prefix),
647 use->rpu_uselen, use->rpu_keeplen);
648 opt_tree = proto_item_add_subtree(tf, ett_icmpv6opt);
649 proto_tree_add_text(opt_tree, NullTVB,
650 off + offsetof(struct rr_pco_use, rpu_uselen),
651 sizeof(use->rpu_uselen), "UseLen: %u", use->rpu_uselen);
652 proto_tree_add_text(opt_tree, NullTVB,
653 off + offsetof(struct rr_pco_use, rpu_keeplen),
654 sizeof(use->rpu_keeplen), "KeepLen: %u", use->rpu_keeplen);
655 tf = proto_tree_add_text(opt_tree, NullTVB,
656 flagoff = off + offsetof(struct rr_pco_use, rpu_ramask),
657 sizeof(use->rpu_ramask), "FlagMask: 0x%x", use->rpu_ramask);
658 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
659 proto_tree_add_text(field_tree, NullTVB, flagoff, 1, "%s",
660 decode_boolean_bitfield(pd[flagoff],
661 ICMP6_RR_PCOUSE_RAFLAGS_ONLINK, 8,
662 "Onlink", "Not onlink"));
663 proto_tree_add_text(field_tree, NullTVB, flagoff, 1, "%s",
664 decode_boolean_bitfield(pd[flagoff],
665 ICMP6_RR_PCOUSE_RAFLAGS_AUTO, 8,
666 "Auto", "Not auto"));
667 tf = proto_tree_add_text(opt_tree, NullTVB,
668 flagoff = off + offsetof(struct rr_pco_use, rpu_raflags),
669 sizeof(use->rpu_raflags), "RAFlags: 0x%x", use->rpu_raflags);
670 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
671 proto_tree_add_text(field_tree, NullTVB, flagoff, 1, "%s",
672 decode_boolean_bitfield(pd[flagoff],
673 ICMP6_RR_PCOUSE_RAFLAGS_ONLINK, 8,
674 "Onlink", "Not onlink"));
675 proto_tree_add_text(field_tree, NullTVB, flagoff, 1, "%s",
676 decode_boolean_bitfield(pd[flagoff],
677 ICMP6_RR_PCOUSE_RAFLAGS_AUTO, 8, "Auto", "Not auto"));
678 if (pntohl(&use->rpu_vltime) == 0xffffffff)
679 proto_tree_add_text(opt_tree, NullTVB,
680 off + offsetof(struct rr_pco_use, rpu_vltime),
681 sizeof(use->rpu_vltime), "Valid Lifetime: infinity");
683 proto_tree_add_text(opt_tree, NullTVB,
684 off + offsetof(struct rr_pco_use, rpu_vltime),
685 sizeof(use->rpu_vltime), "Valid Lifetime: %u",
686 pntohl(&use->rpu_vltime));
687 if (pntohl(&use->rpu_pltime) == 0xffffffff)
688 proto_tree_add_text(opt_tree, NullTVB,
689 off + offsetof(struct rr_pco_use, rpu_pltime),
690 sizeof(use->rpu_pltime), "Preferred Lifetime: infinity");
692 proto_tree_add_text(opt_tree, NullTVB,
693 off + offsetof(struct rr_pco_use, rpu_pltime),
694 sizeof(use->rpu_pltime), "Preferred Lifetime: %u",
695 pntohl(&use->rpu_pltime));
696 tf = proto_tree_add_text(opt_tree, NullTVB,
697 flagoff = off + offsetof(struct rr_pco_use, rpu_flags),
698 sizeof(use->rpu_flags), "Flags: 0x%08x",
699 pntohl(&use->rpu_flags));
700 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
701 proto_tree_add_text(field_tree, NullTVB, flagoff, 4, "%s",
702 decode_boolean_bitfield(pd[flagoff],
703 ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, 32,
704 "Decrement valid lifetime", "No decrement valid lifetime"));
705 proto_tree_add_text(field_tree, NullTVB, flagoff, 4, "%s",
706 decode_boolean_bitfield(pd[flagoff],
707 ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, 32,
708 "Decrement preferred lifetime",
709 "No decrement preferred lifetime"));
710 proto_tree_add_text(opt_tree, NullTVB,
711 off + offsetof(struct rr_pco_use, rpu_prefix),
712 sizeof(use->rpu_prefix), "UsePrefix: %s",
713 ip6_to_str(&use->rpu_prefix));
720 dissect_icmpv6(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
722 proto_tree *icmp6_tree, *field_tree;
723 proto_item *ti, *tf = NULL;
724 struct icmp6_hdr *dp;
725 struct icmp6_nodeinfo *ni = NULL;
726 char *codename, *typename;
727 char *colcodename, *coltypename;
730 OLD_CHECK_DISPLAY_AS_DATA(proto_icmpv6, pd, offset, fd, tree);
732 dp = (struct icmp6_hdr *)&pd[offset];
733 codename = typename = colcodename = coltypename = "Unknown";
735 switch (dp->icmp6_type) {
736 case ICMP6_DST_UNREACH:
737 typename = coltypename = "Unreachable";
738 switch (dp->icmp6_code) {
739 case ICMP6_DST_UNREACH_NOROUTE:
740 codename = colcodename = "Route unreachable";
742 case ICMP6_DST_UNREACH_ADMIN:
743 codename = colcodename = "Administratively prohibited";
745 case ICMP6_DST_UNREACH_NOTNEIGHBOR:
746 codename = colcodename = "Not a neighbor";
748 case ICMP6_DST_UNREACH_ADDR:
749 codename = colcodename = "Address unreachable";
751 case ICMP6_DST_UNREACH_NOPORT:
752 codename = colcodename = "Port unreachable";
756 case ICMP6_PACKET_TOO_BIG:
757 typename = coltypename = "Too big";
758 codename = colcodename = NULL;
760 case ICMP6_TIME_EXCEEDED:
761 typename = coltypename = "Time exceeded";
762 switch (dp->icmp6_code) {
763 case ICMP6_TIME_EXCEED_TRANSIT:
764 codename = colcodename = "In-transit";
766 case ICMP6_TIME_EXCEED_REASSEMBLY:
767 codename = colcodename = "Reassembly";
771 case ICMP6_PARAM_PROB:
772 typename = coltypename = "Parameter problem";
773 switch (dp->icmp6_code) {
774 case ICMP6_PARAMPROB_HEADER:
775 codename = colcodename = "Header";
777 case ICMP6_PARAMPROB_NEXTHEADER:
778 codename = colcodename = "Next header";
780 case ICMP6_PARAMPROB_OPTION:
781 codename = colcodename = "Option";
785 case ICMP6_ECHO_REQUEST:
786 typename = coltypename = "Echo request";
787 codename = colcodename = NULL;
789 case ICMP6_ECHO_REPLY:
790 typename = coltypename = "Echo reply";
791 codename = colcodename = NULL;
793 case ICMP6_MEMBERSHIP_QUERY:
794 typename = coltypename = "Multicast listener query";
795 codename = colcodename = NULL;
797 case ICMP6_MEMBERSHIP_REPORT:
798 typename = coltypename = "Multicast listener report";
799 codename = colcodename = NULL;
801 case ICMP6_MEMBERSHIP_REDUCTION:
802 typename = coltypename = "Multicast listener done";
803 codename = colcodename = NULL;
805 case ND_ROUTER_SOLICIT:
806 typename = coltypename = "Router solicitation";
807 codename = colcodename = NULL;
808 len = sizeof(struct nd_router_solicit);
810 case ND_ROUTER_ADVERT:
811 typename = coltypename = "Router advertisement";
812 codename = colcodename = NULL;
813 len = sizeof(struct nd_router_advert);
815 case ND_NEIGHBOR_SOLICIT:
816 typename = coltypename = "Neighbor solicitation";
817 codename = colcodename = NULL;
818 len = sizeof(struct nd_neighbor_solicit);
820 case ND_NEIGHBOR_ADVERT:
821 typename = coltypename = "Neighbor advertisement";
822 codename = colcodename = NULL;
823 len = sizeof(struct nd_neighbor_advert);
826 typename = coltypename = "Redirect";
827 codename = colcodename = NULL;
828 len = sizeof(struct nd_redirect);
830 case ICMP6_ROUTER_RENUMBERING:
831 typename = coltypename = "Router renumbering";
832 switch (dp->icmp6_code) {
833 case ICMP6_ROUTER_RENUMBERING_COMMAND:
834 codename = colcodename = "Command";
836 case ICMP6_ROUTER_RENUMBERING_RESULT:
837 codename = colcodename = "Result";
839 case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
840 codename = colcodename = "Sequence number reset";
843 len = sizeof(struct icmp6_router_renum);
847 ni = (struct icmp6_nodeinfo *)dp;
848 if (ni->ni_type == ICMP6_NI_QUERY) {
849 typename = coltypename = "Node information query";
850 switch (ni->ni_code) {
851 case ICMP6_NI_SUBJ_IPV6:
852 codename = "Query subject = IPv6 addresses";
854 case ICMP6_NI_SUBJ_FQDN:
855 if (IS_DATA_IN_FRAME(offset + sizeof(*ni)))
856 codename = "Query subject = DNS name";
858 codename = "Query subject = empty";
860 case ICMP6_NI_SUBJ_IPV4:
861 codename = "Query subject = IPv4 addresses";
865 typename = coltypename = "Node information reply";
866 switch (ni->ni_code) {
867 case ICMP6_NI_SUCCESS:
868 codename = "Successful";
870 case ICMP6_NI_REFUSED:
871 codename = "Refused";
873 case ICMP6_NI_UNKNOWN:
874 codename = "Unknown query type";
878 colcodename = val_to_str(pntohs(&ni->ni_qtype), names_nodeinfo_qtype,
880 len = sizeof(struct icmp6_nodeinfo);
884 if (check_col(fd, COL_PROTOCOL))
885 col_add_str(fd, COL_PROTOCOL, "ICMPv6");
886 if (check_col(fd, COL_INFO)) {
887 char typebuf[256], codebuf[256];
889 if (coltypename && strcmp(coltypename, "Unknown") == 0) {
890 snprintf(typebuf, sizeof(typebuf), "Unknown (0x%02x)",
892 coltypename = typebuf;
894 if (colcodename && strcmp(colcodename, "Unknown") == 0) {
895 snprintf(codebuf, sizeof(codebuf), "Unknown (0x%02x)",
897 colcodename = codebuf;
900 col_add_fstr(fd, COL_INFO, "%s (%s)", coltypename, colcodename);
902 col_add_fstr(fd, COL_INFO, "%s", coltypename);
907 /* !!! specify length */
908 ti = proto_tree_add_item(tree, proto_icmpv6, NullTVB, offset, len, FALSE);
909 icmp6_tree = proto_item_add_subtree(ti, ett_icmpv6);
911 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_type, NullTVB,
912 offset + offsetof(struct icmp6_hdr, icmp6_type), 1,
914 "Type: 0x%02x (%s)", dp->icmp6_type, typename);
916 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_code, NullTVB,
917 offset + offsetof(struct icmp6_hdr, icmp6_code), 1,
919 "Code: 0x%02x (%s)", dp->icmp6_code, codename);
921 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_code, NullTVB,
922 offset + offsetof(struct icmp6_hdr, icmp6_code), 1,
924 "Code: 0x%02x", dp->icmp6_code);
926 proto_tree_add_uint(icmp6_tree, hf_icmpv6_checksum, NullTVB,
927 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
928 (guint16)htons(dp->icmp6_cksum));
931 switch (dp->icmp6_type) {
932 case ICMP6_DST_UNREACH:
933 case ICMP6_TIME_EXCEEDED:
934 /* tiny sanity check */
935 if ((pd[offset + sizeof(*dp)] & 0xf0) == 0x60) {
936 dissect_ipv6(pd, offset + sizeof(*dp), fd, icmp6_tree);
938 old_dissect_data(pd, offset + sizeof(*dp), fd, icmp6_tree);
941 case ICMP6_PACKET_TOO_BIG:
942 proto_tree_add_text(icmp6_tree, NullTVB,
943 offset + offsetof(struct icmp6_hdr, icmp6_mtu), 4,
944 "MTU: %d", pntohl(&dp->icmp6_mtu));
945 /* tiny sanity check */
946 if ((pd[offset + sizeof(*dp)] & 0xf0) == 0x60) {
947 dissect_ipv6(pd, offset + sizeof(*dp), fd, icmp6_tree);
949 old_dissect_data(pd, offset + sizeof(*dp), fd, icmp6_tree);
952 case ICMP6_PARAM_PROB:
953 proto_tree_add_text(icmp6_tree, NullTVB,
954 offset + offsetof(struct icmp6_hdr, icmp6_pptr), 4,
955 "Problem pointer: 0x%04x", pntohl(&dp->icmp6_pptr));
956 /* tiny sanity check */
957 if ((pd[offset + sizeof(*dp)] & 0xf0) == 0x60) {
958 dissect_ipv6(pd, offset + sizeof(*dp), fd, icmp6_tree);
960 old_dissect_data(pd, offset + sizeof(*dp), fd, icmp6_tree);
963 case ICMP6_ECHO_REQUEST:
964 case ICMP6_ECHO_REPLY:
965 proto_tree_add_text(icmp6_tree, NullTVB,
966 offset + offsetof(struct icmp6_hdr, icmp6_id), 2,
967 "ID: 0x%04x", (guint16)ntohs(dp->icmp6_id));
968 proto_tree_add_text(icmp6_tree, NullTVB,
969 offset + offsetof(struct icmp6_hdr, icmp6_seq), 2,
970 "Sequence: 0x%04x", (guint16)ntohs(dp->icmp6_seq));
971 old_dissect_data(pd, offset + sizeof(*dp), fd, icmp6_tree);
973 case ICMP6_MEMBERSHIP_QUERY:
974 case ICMP6_MEMBERSHIP_REPORT:
975 case ICMP6_MEMBERSHIP_REDUCTION:
976 proto_tree_add_text(icmp6_tree, NullTVB,
977 offset + offsetof(struct icmp6_hdr, icmp6_maxdelay), 2,
978 "Maximum response delay: %d",
979 (guint16)ntohs(dp->icmp6_maxdelay));
980 proto_tree_add_text(icmp6_tree, NullTVB, offset + sizeof(*dp), 16,
981 "Multicast Address: %s",
982 ip6_to_str((struct e_in6_addr *)(dp + 1)));
984 case ND_ROUTER_SOLICIT:
985 dissect_icmpv6opt(pd, offset + sizeof(*dp), fd, icmp6_tree);
987 case ND_ROUTER_ADVERT:
989 struct nd_router_advert *ra = (struct nd_router_advert *)dp;
993 proto_tree_add_text(icmp6_tree, NullTVB,
994 offset + offsetof(struct nd_router_advert, nd_ra_curhoplimit),
995 1, "Cur hop limit: %d", ra->nd_ra_curhoplimit);
997 flagoff = offset + offsetof(struct nd_router_advert, nd_ra_flags_reserved);
998 ra_flags = pntohl(&pd[flagoff]);
999 tf = proto_tree_add_text(icmp6_tree, NullTVB, flagoff, 4, "Flags: 0x%08x", ra_flags);
1000 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1001 proto_tree_add_text(field_tree, NullTVB, flagoff, 4, "%s",
1002 decode_boolean_bitfield(ra_flags,
1003 0x80000000, 32, "Managed", "Not managed"));
1004 proto_tree_add_text(field_tree, NullTVB, flagoff, 4, "%s",
1005 decode_boolean_bitfield(ra_flags,
1006 0x40000000, 32, "Other", "Not other"));
1008 proto_tree_add_text(icmp6_tree, NullTVB,
1009 offset + offsetof(struct nd_router_advert, nd_ra_router_lifetime),
1010 2, "Router lifetime: %d",
1011 (guint16)ntohs(ra->nd_ra_router_lifetime));
1012 proto_tree_add_text(icmp6_tree, NullTVB,
1013 offset + offsetof(struct nd_router_advert, nd_ra_reachable), 4,
1014 "Reachable time: %d", pntohl(&ra->nd_ra_reachable));
1015 proto_tree_add_text(icmp6_tree, NullTVB,
1016 offset + offsetof(struct nd_router_advert, nd_ra_retransmit), 4,
1017 "Retrans time: %d", pntohl(&ra->nd_ra_retransmit));
1018 dissect_icmpv6opt(pd, offset + sizeof(struct nd_router_advert), fd, icmp6_tree);
1021 case ND_NEIGHBOR_SOLICIT:
1023 struct nd_neighbor_solicit *ns = (struct nd_neighbor_solicit *)dp;
1025 proto_tree_add_text(icmp6_tree, NullTVB,
1026 offset + offsetof(struct nd_neighbor_solicit, nd_ns_target), 16,
1029 get_hostname6(&ns->nd_ns_target),
1033 ip6_to_str(&ns->nd_ns_target));
1035 dissect_icmpv6opt(pd, offset + sizeof(*ns), fd, icmp6_tree);
1038 case ND_NEIGHBOR_ADVERT:
1040 int flagoff, targetoff;
1042 struct e_in6_addr *na_target_p;
1044 flagoff = offset + offsetof(struct nd_neighbor_advert, nd_na_flags_reserved);
1045 na_flags = pntohl(&pd[flagoff]);
1047 tf = proto_tree_add_text(icmp6_tree, NullTVB, flagoff, 4, "Flags: 0x%08x", na_flags);
1048 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1049 proto_tree_add_text(field_tree, NullTVB, flagoff, 4, "%s",
1050 decode_boolean_bitfield(na_flags,
1051 ND_NA_FLAG_ROUTER, 32, "Router", "Not router"));
1052 proto_tree_add_text(field_tree, NullTVB, flagoff, 4, "%s",
1053 decode_boolean_bitfield(na_flags,
1054 ND_NA_FLAG_SOLICITED, 32, "Solicited", "Not adverted"));
1055 proto_tree_add_text(field_tree, NullTVB, flagoff, 4, "%s",
1056 decode_boolean_bitfield(na_flags,
1057 ND_NA_FLAG_OVERRIDE, 32, "Override", "Not override"));
1059 targetoff = offset + offsetof(struct nd_neighbor_advert, nd_na_target);
1060 na_target_p = (struct e_in6_addr*) &pd[targetoff];
1061 proto_tree_add_text(icmp6_tree, NullTVB, targetoff, 16,
1064 get_hostname6(na_target_p),
1068 ip6_to_str(na_target_p));
1070 dissect_icmpv6opt(pd, offset + sizeof(struct nd_neighbor_advert), fd, icmp6_tree);
1075 struct nd_redirect *rd = (struct nd_redirect *)dp;
1077 proto_tree_add_text(icmp6_tree, NullTVB,
1078 offset + offsetof(struct nd_redirect, nd_rd_target), 16,
1081 get_hostname6(&rd->nd_rd_target),
1085 ip6_to_str(&rd->nd_rd_target));
1087 proto_tree_add_text(icmp6_tree, NullTVB,
1088 offset + offsetof(struct nd_redirect, nd_rd_dst), 16,
1090 "Destination: %s (%s)",
1091 get_hostname6(&rd->nd_rd_dst),
1095 ip6_to_str(&rd->nd_rd_dst));
1097 dissect_icmpv6opt(pd, offset + sizeof(*rd), fd, icmp6_tree);
1100 case ICMP6_ROUTER_RENUMBERING:
1101 dissect_rrenum(pd, offset, fd, icmp6_tree);
1103 case ICMP6_NI_QUERY:
1104 case ICMP6_NI_REPLY:
1105 ni = (struct icmp6_nodeinfo *)dp;
1106 proto_tree_add_text(icmp6_tree, NullTVB,
1107 offset + offsetof(struct icmp6_nodeinfo, ni_qtype),
1108 sizeof(ni->ni_qtype),
1109 "Query type: 0x%04x (%s)", pntohs(&ni->ni_qtype),
1110 val_to_str(pntohs(&ni->ni_qtype), names_nodeinfo_qtype,
1112 dissect_nodeinfo(pd, offset, fd, icmp6_tree);
1115 old_dissect_data(pd, offset + sizeof(*dp), fd, tree);
1122 proto_register_icmpv6(void)
1124 static hf_register_info hf[] = {
1126 { "Type", "icmpv6.type", FT_UINT8, BASE_HEX, NULL, 0x0,
1129 { "Code", "icmpv6.code", FT_UINT8, BASE_HEX, NULL, 0x0,
1131 { &hf_icmpv6_checksum,
1132 { "Checksum", "icmpv6.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
1135 static gint *ett[] = {
1140 &ett_nodeinfo_subject4,
1141 &ett_nodeinfo_subject6,
1142 &ett_nodeinfo_node4,
1143 &ett_nodeinfo_node6,
1144 &ett_nodeinfo_nodebitmap,
1145 &ett_nodeinfo_nodedns,
1148 proto_icmpv6 = proto_register_protocol("Internet Control Message Protocol v6",
1150 proto_register_field_array(proto_icmpv6, hf, array_length(hf));
1151 proto_register_subtree_array(ett, array_length(ett));
1155 proto_reg_handoff_icmpv6(void)
1157 old_dissector_add("ip.proto", IP_PROTO_ICMPV6, dissect_icmpv6);