2 * Routines for ICMPv6 packet disassembly
4 * $Id: packet-icmpv6.c,v 1.37 2001/02/28 19:33:49 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 const value_string names_nodeinfo_qtype[] = {
83 { NI_QTYPE_NOOP, "NOOP" },
84 { NI_QTYPE_SUPTYPES, "Supported query types" },
85 { NI_QTYPE_DNSNAME, "DNS name" },
86 { NI_QTYPE_NODEADDR, "Node addresses" },
87 { NI_QTYPE_IPV4ADDR, "IPv4 node addresses" },
91 static const value_string names_rrenum_matchcode[] = {
92 { RPM_PCO_ADD, "Add" },
93 { RPM_PCO_CHANGE, "Change" },
94 { RPM_PCO_SETGLOBAL, "Set Global" },
99 dissect_icmpv6opt(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
101 proto_tree *icmp6opt_tree, *field_tree;
103 struct nd_opt_hdr *opt;
111 if (!IS_DATA_IN_FRAME(offset))
114 opt = (struct nd_opt_hdr *)&pd[offset];
115 len = opt->nd_opt_len << 3;
117 /* !!! specify length */
118 ti = proto_tree_add_text(tree, NullTVB, offset, len, "ICMPv6 options");
119 icmp6opt_tree = proto_item_add_subtree(ti, ett_icmpv6opt);
121 switch (opt->nd_opt_type) {
122 case ND_OPT_SOURCE_LINKADDR:
123 typename = "Source link-layer address";
125 case ND_OPT_TARGET_LINKADDR:
126 typename = "Target link-layer address";
128 case ND_OPT_PREFIX_INFORMATION:
129 typename = "Prefix information";
131 case ND_OPT_REDIRECTED_HEADER:
132 typename = "Redirected header";
137 case ND_OPT_ADVERTISEMENT_INTERVAL:
138 typename = "Advertisement Interval";
140 case ND_OPT_HOME_AGENT_INFORMATION:
141 typename = "Home Agent Information";
145 typename = "Unknown";
149 proto_tree_add_text(icmp6opt_tree, NullTVB,
150 offset + offsetof(struct nd_opt_hdr, nd_opt_type), 1,
151 "Type: 0x%02x (%s)", opt->nd_opt_type, typename);
152 proto_tree_add_text(icmp6opt_tree, NullTVB,
153 offset + offsetof(struct nd_opt_hdr, nd_opt_len), 1,
154 "Length: %d bytes (0x%02x)", opt->nd_opt_len << 3, opt->nd_opt_len);
157 switch (opt->nd_opt_type) {
158 case ND_OPT_SOURCE_LINKADDR:
159 case ND_OPT_TARGET_LINKADDR:
164 len = (opt->nd_opt_len << 3) - sizeof(*opt);
165 t = (char *)malloc(len * 3);
166 memset(t, 0, len * 3);
167 p = &pd[offset + sizeof(*opt)];
168 for (i = 0; i < len; i++) {
171 sprintf(&t[i * 3], "%02x", p[i] & 0xff);
173 proto_tree_add_text(icmp6opt_tree, NullTVB,
174 offset + sizeof(*opt), len, "Link-layer address: %s", t);
177 case ND_OPT_PREFIX_INFORMATION:
179 struct nd_opt_prefix_info *pi = (struct nd_opt_prefix_info *)opt;
181 proto_tree_add_text(icmp6opt_tree, NullTVB,
182 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_prefix_len),
183 1, "Prefix length: %d", pi->nd_opt_pi_prefix_len);
185 flagoff = offsetof(struct nd_opt_prefix_info, nd_opt_pi_flags_reserved);
186 tf = proto_tree_add_text(icmp6opt_tree, NullTVB, flagoff, 1, "Flags: 0x%02x",
187 pntohl(&pi->nd_opt_pi_flags_reserved));
188 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
189 proto_tree_add_text(field_tree, NullTVB, flagoff, 1, "%s",
190 decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
191 0x80, 8, "Onlink", "Not onlink"));
192 proto_tree_add_text(field_tree, NullTVB, flagoff, 1, "%s",
193 decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
194 0x40, 8, "Auto", "Not auto"));
195 /* BT INSERT BEGIN */
196 proto_tree_add_text(field_tree, NullTVB, flagoff, 1, "%s",
197 decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
198 0x20, 8, "Router Address", "Not router address"));
200 proto_tree_add_text(icmp6opt_tree, NullTVB,
201 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_valid_time),
202 4, "Valid lifetime: 0x%08x",
203 pntohl(&pi->nd_opt_pi_valid_time));
204 proto_tree_add_text(icmp6opt_tree, NullTVB,
205 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_preferred_time),
206 4, "Preferred lifetime: 0x%08x",
207 pntohl(&pi->nd_opt_pi_preferred_time));
208 proto_tree_add_text(icmp6opt_tree, NullTVB,
209 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_prefix),
210 16, "Prefix: %s", ip6_to_str(&pi->nd_opt_pi_prefix));
213 case ND_OPT_REDIRECTED_HEADER:
214 proto_tree_add_text(icmp6opt_tree, NullTVB,
215 offset + 8, (opt->nd_opt_len << 3) - 8, "Redirected packet");
216 /* tiny sanity check */
217 if ((pd[offset + 8] & 0xf0) == 0x60)
218 dissect_ipv6(pd, offset + 8, fd, icmp6opt_tree);
220 old_dissect_data(pd, offset + 8, fd, icmp6opt_tree);
224 struct nd_opt_mtu *pi = (struct nd_opt_mtu *)opt;
225 proto_tree_add_text(icmp6opt_tree, NullTVB,
226 offset + offsetof(struct nd_opt_mtu, nd_opt_mtu_mtu), 4,
227 "MTU: %d", pntohl(&pi->nd_opt_mtu_mtu));
230 /* BT INSERT BEGIN */
231 case ND_OPT_ADVERTISEMENT_INTERVAL:
233 struct nd_opt_adv_int *pi = (struct nd_opt_adv_int *)opt;
234 proto_tree_add_text(icmp6opt_tree, NullTVB,
235 offset + offsetof(struct nd_opt_adv_int, nd_opt_adv_int_advint), 4,
236 "Advertisement Interval: %d", pntohl(&pi->nd_opt_adv_int_advint));
239 case ND_OPT_HOME_AGENT_INFORMATION:
241 struct nd_opt_ha_info *pi = (struct nd_opt_ha_info *)opt;
242 proto_tree_add_text(icmp6opt_tree, NullTVB,
243 offset + offsetof(struct nd_opt_ha_info, nd_opt_ha_info_ha_pref),
244 2, "Home Agent Preference: %d",
245 pntohs(&pi->nd_opt_ha_info_ha_pref));
246 proto_tree_add_text(icmp6opt_tree, NullTVB,
247 offset + offsetof(struct nd_opt_ha_info, nd_opt_ha_info_ha_life),
248 2, "Home Agent Lifetime: %d",
249 pntohs(&pi->nd_opt_ha_info_ha_life));
255 if (opt->nd_opt_len == 0) {
256 proto_tree_add_text(icmp6opt_tree, NullTVB,
257 offset + offsetof(struct nd_opt_hdr, nd_opt_len), 1,
258 "Invalid option length: %d",
263 offset += (opt->nd_opt_len << 3);
268 * draft-ietf-ipngwg-icmp-name-lookups-06.txt
269 * Note that the packet format was changed several times in the past.
273 bitrange0(v, s, buf, buflen)
293 ep = buf + buflen - 1;
294 memset(buf, 0, buflen);
297 /* shift till we have 0x01 */
298 if ((v & 0x01) == 0) {
301 v >>= 4; off += 4; continue;
303 v >>= 3; off += 3; continue;
304 case 0x04: case 0x0c:
305 v >>= 2; off += 2; continue;
307 v >>= 1; off += 1; continue;
311 /* we have 0x01 with us */
312 for (i = 0; i < 32 - off; i++) {
313 if ((v & (0x01 << i)) == 0)
317 l = snprintf(p, ep - p, ",%d", s + off);
319 l = snprintf(p, ep - p, ",%d-%d", s + off,
333 bitrange(u_char *p, int l, int s)
335 static char buf[1024];
339 memset(buf, 0, sizeof(buf));
341 eq = buf + sizeof(buf) - 1;
342 for (i = 0; i < l; i++) {
343 if (bitrange0(pntohl(p + i * 4), s + i * 4, q, eq - q) == NULL) {
344 if (q != buf && q + 5 < buf + sizeof(buf))
345 strncpy(q, ",...", 5);
354 dissect_nodeinfo(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
356 proto_tree *field_tree;
358 struct icmp6_nodeinfo *ni;
363 char dname[MAXDNAME];
365 ni = (struct icmp6_nodeinfo *)&pd[offset];
368 flags = pntohs(&ni->ni_flags);
369 tf = proto_tree_add_text(tree, NullTVB,
370 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
371 sizeof(ni->ni_flags), "Flags: 0x%04x", flags);
372 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_flag);
373 switch (pntohs(&ni->ni_qtype)) {
374 case NI_QTYPE_SUPTYPES:
375 if (ni->ni_type == ICMP6_NI_QUERY) {
376 proto_tree_add_text(field_tree, NullTVB,
377 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
378 sizeof(ni->ni_flags), "%s",
379 decode_boolean_bitfield(flags, NI_SUPTYPE_FLAG_COMPRESS, sizeof(flags) * 8,
380 "Compressed reply supported",
381 "No compressed reply support"));
383 proto_tree_add_text(field_tree, NullTVB,
384 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
385 sizeof(ni->ni_flags), "%s",
386 decode_boolean_bitfield(flags, NI_SUPTYPE_FLAG_COMPRESS, sizeof(flags) * 8,
387 "Compressed", "Not compressed"));
390 case NI_QTYPE_DNSNAME:
391 if (ni->ni_type == ICMP6_NI_REPLY) {
392 proto_tree_add_text(field_tree, NullTVB,
393 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
394 sizeof(ni->ni_flags), "%s",
395 decode_boolean_bitfield(flags, NI_FQDN_FLAG_VALIDTTL, sizeof(flags) * 8,
396 "Valid TTL field", "Meaningless TTL field"));
399 case NI_QTYPE_NODEADDR:
400 proto_tree_add_text(field_tree, NullTVB,
401 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
402 sizeof(ni->ni_flags), "%s",
403 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_GLOBAL, sizeof(flags) * 8,
405 "Not global address"));
406 proto_tree_add_text(field_tree, NullTVB,
407 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
408 sizeof(ni->ni_flags), "%s",
409 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_SITELOCAL, sizeof(flags) * 8,
410 "Site-local address",
411 "Not site-local address"));
412 proto_tree_add_text(field_tree, NullTVB,
413 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
414 sizeof(ni->ni_flags), "%s",
415 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_LINKLOCAL, sizeof(flags) * 8,
416 "Link-local address",
417 "Not link-local address"));
418 proto_tree_add_text(field_tree, NullTVB,
419 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
420 sizeof(ni->ni_flags), "%s",
421 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_COMPAT, sizeof(flags) * 8,
422 "IPv4 compatible/mapped address",
423 "Not IPv4 compatible/mapped address"));
425 case NI_QTYPE_IPV4ADDR:
426 proto_tree_add_text(field_tree, NullTVB,
427 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
428 sizeof(ni->ni_flags), "%s",
429 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_ALL, sizeof(flags) * 8,
430 "All unicast address",
431 "Unicast addresses on the queried interface"));
432 proto_tree_add_text(field_tree, NullTVB,
433 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
434 sizeof(ni->ni_flags), "%s",
435 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_TRUNCATE, sizeof(flags) * 8,
436 "Truncated", "Not truncated"));
441 proto_tree_add_text(tree, NullTVB,
442 offset + offsetof(struct icmp6_nodeinfo, icmp6_ni_nonce[0]),
443 sizeof(ni->icmp6_ni_nonce), "Nonce: 0x%08x%08x",
444 pntohl(&ni->icmp6_ni_nonce[0]), pntohl(&ni->icmp6_ni_nonce[4]));
446 /* offset for "the rest of data" */
450 if (!IS_DATA_IN_FRAME(offset + sizeof(*ni)))
452 if (ni->ni_type == ICMP6_NI_QUERY) {
453 switch (ni->ni_code) {
454 case ICMP6_NI_SUBJ_IPV6:
455 n = pi.captured_len - (offset + sizeof(*ni));
456 n /= sizeof(struct e_in6_addr);
457 tf = proto_tree_add_text(tree, NullTVB,
458 offset + sizeof(*ni), END_OF_FRAME, "IPv6 subject addresses");
459 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_subject6);
460 p = (u_char *)(ni + 1);
461 for (i = 0; i < n; i++) {
462 proto_tree_add_text(field_tree, NullTVB,
463 p - pd, sizeof(struct e_in6_addr),
464 "%s", ip6_to_str((struct e_in6_addr *)p));
465 p += sizeof(struct e_in6_addr);
467 off = pi.captured_len - offset;
469 case ICMP6_NI_SUBJ_FQDN:
470 l = get_dns_name(pd, offset + sizeof(*ni), offset + sizeof(*ni),
471 dname, sizeof(dname));
472 if (IS_DATA_IN_FRAME(offset + sizeof(*ni) + l) &&
473 pd[offset + sizeof(*ni) + l] == 0) {
475 proto_tree_add_text(tree, NullTVB, offset + sizeof(*ni), l,
476 "DNS label: %s (truncated)", dname);
478 proto_tree_add_text(tree, NullTVB, offset + sizeof(*ni), l,
479 "DNS label: %s", dname);
481 off = offset + sizeof(*ni) + l;
483 case ICMP6_NI_SUBJ_IPV4:
484 n = pi.captured_len - (offset + sizeof(*ni));
485 n /= sizeof(guint32);
486 tf = proto_tree_add_text(tree, NullTVB,
487 offset + sizeof(*ni), END_OF_FRAME, "IPv4 subject addresses");
488 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_subject4);
489 p = (u_char *)(ni + 1);
490 for (i = 0; i < n; i++) {
491 proto_tree_add_text(field_tree, NullTVB,
492 p - pd, sizeof(guint32), "%s", ip_to_str(p));
493 p += sizeof(guint32);
495 off = pi.captured_len - offset;
499 switch (pntohs(&ni->ni_qtype)) {
502 case NI_QTYPE_SUPTYPES:
503 p = (u_char *)(ni + 1);
504 tf = proto_tree_add_text(tree, NullTVB,
505 offset + sizeof(*ni), END_OF_FRAME,
506 "Supported type bitmap%s",
507 (flags & 0x0001) ? ", compressed" : "");
508 field_tree = proto_item_add_subtree(tf,
509 ett_nodeinfo_nodebitmap);
511 while (IS_DATA_IN_FRAME(p - pd)) {
512 if ((flags & 0x0001) == 0) {
513 l = pi.captured_len - (offset + sizeof(*ni));
514 l /= sizeof(guint32);
517 if (!IS_DATA_IN_FRAME(p + sizeof(guint32) - 1 - pd))
520 i = pntohs(p + sizeof(guint16)); /*skip*/
522 if (n + l * 32 > (1 << 16))
524 if (n + (l + i) * 32 > (1 << 16))
526 if ((flags & 0x0001) == 0) {
527 proto_tree_add_text(field_tree, NullTVB, p - pd,
528 l * 4, "Bitmap (%d to %d): %s", n, n + l * 32 - 1,
532 proto_tree_add_text(field_tree, NullTVB, p - pd,
533 4 + l * 4, "Bitmap (%d to %d): %s", n, n + l * 32 - 1,
534 bitrange(p + 4, l, n));
537 n += l * 32 + i * 32;
539 off = pi.captured_len - offset;
541 case NI_QTYPE_DNSNAME:
542 proto_tree_add_text(tree, NullTVB, offset + sizeof(*ni),
543 sizeof(gint32), "TTL: %d", (gint32)pntohl(ni + 1));
544 tf = proto_tree_add_text(tree, NullTVB,
545 offset + sizeof(*ni) + sizeof(guint32), END_OF_FRAME,
547 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_nodedns);
549 i = offset + sizeof(*ni) + sizeof(guint32);
550 while (i < pi.captured_len) {
551 l = get_dns_name(pd, i, offset + sizeof(*ni), dname,
553 if (IS_DATA_IN_FRAME(i + l) && pd[i + l] == 0) {
555 proto_tree_add_text(field_tree, NullTVB, i, l,
556 "DNS label: %s (truncated)", dname);
558 proto_tree_add_text(field_tree, NullTVB, i, l,
559 "DNS label: %s", dname);
563 off = pi.captured_len - offset;
565 case NI_QTYPE_NODEADDR:
566 n = pi.captured_len - (offset + sizeof(*ni));
567 n /= sizeof(struct e_in6_addr) + sizeof(gint32);;
568 tf = proto_tree_add_text(tree, NullTVB,
569 offset + sizeof(*ni), END_OF_FRAME, "IPv6 node addresses");
570 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_node6);
571 p = (u_char *)(ni + 1);
572 for (i = 0; i < n; i++) {
573 proto_tree_add_text(field_tree, NullTVB,
574 p - pd, sizeof(struct e_in6_addr) + sizeof(gint32),
575 "%s (TTL %d)", ip6_to_str((struct e_in6_addr *)p),
576 (gint32)pntohl(p + sizeof(struct e_in6_addr)));
577 p += sizeof(struct e_in6_addr) + sizeof(gint32);
579 off = pi.captured_len - offset;
581 case NI_QTYPE_IPV4ADDR:
582 n = pi.captured_len - (offset + sizeof(*ni));
583 n /= sizeof(guint32);
584 tf = proto_tree_add_text(tree, NullTVB,
585 offset + sizeof(*ni), END_OF_FRAME, "IPv4 node addresses");
586 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_node4);
587 p = (u_char *)(ni + 1);
588 for (i = 0; i < n; i++) {
589 proto_tree_add_text(field_tree, NullTVB,
590 p - pd, sizeof(guint32), "%s", ip_to_str(p));
591 p += sizeof(guint32);
593 off = pi.captured_len - offset;
599 /* the rest of data */
600 old_dissect_data(pd, offset + off, fd, tree);
604 dissect_rrenum(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
606 proto_tree *field_tree, *opt_tree;
608 struct icmp6_router_renum *rr = (struct icmp6_router_renum *)&pd[offset];
609 struct rr_pco_match *match;
610 struct rr_pco_use *use;
613 proto_tree_add_text(tree, NullTVB,
614 offset + offsetof(struct icmp6_router_renum, rr_seqnum), 4,
615 "Sequence number: 0x%08x", pntohl(&rr->rr_seqnum));
616 proto_tree_add_text(tree, NullTVB,
617 offset + offsetof(struct icmp6_router_renum, rr_segnum), 1,
618 "Segment number: 0x%02x", rr->rr_segnum);
620 flagoff = offset + offsetof(struct icmp6_router_renum, rr_flags);
621 tf = proto_tree_add_text(tree, NullTVB, flagoff, 1,
622 "Flags: 0x%02x", pd[flagoff]);
623 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
624 proto_tree_add_text(field_tree, NullTVB, flagoff, 1, "%s",
625 decode_boolean_bitfield(pd[flagoff], 0x80, 8,
626 "Test command", "Not test command"));
627 proto_tree_add_text(field_tree, NullTVB, flagoff, 1, "%s",
628 decode_boolean_bitfield(pd[flagoff], 0x40, 8,
629 "Result requested", "Result not requested"));
630 proto_tree_add_text(field_tree, NullTVB, flagoff, 1, "%s",
631 decode_boolean_bitfield(pd[flagoff], 0x20, 8,
632 "All interfaces", "Not all interfaces"));
633 proto_tree_add_text(field_tree, NullTVB, flagoff, 1, "%s",
634 decode_boolean_bitfield(pd[flagoff], 0x10, 8,
635 "Site specific", "Not site specific"));
636 proto_tree_add_text(field_tree, NullTVB, flagoff, 1, "%s",
637 decode_boolean_bitfield(pd[flagoff], 0x08, 8,
638 "Processed previously", "Complete result"));
640 proto_tree_add_text(tree, NullTVB,
641 offset + offsetof(struct icmp6_router_renum, rr_maxdelay), 2,
642 "Max delay: 0x%04x", pntohs(&rr->rr_maxdelay));
643 old_dissect_data(pd, offset + sizeof(*rr), fd, tree); /*XXX*/
645 if (rr->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) {
646 off = offset + sizeof(*rr);
647 match = (struct rr_pco_match *)&pd[off];
648 tf = proto_tree_add_text(tree, NullTVB, off, sizeof(*match),
649 "Match-Prefix: %s/%u (%u-%u)", ip6_to_str(&match->rpm_prefix),
650 match->rpm_matchlen, match->rpm_minlen, match->rpm_maxlen);
651 opt_tree = proto_item_add_subtree(tf, ett_icmpv6opt);
652 proto_tree_add_text(opt_tree, NullTVB,
653 off + offsetof(struct rr_pco_match, rpm_code),
654 sizeof(match->rpm_code), "OpCode: %s (%u)",
655 val_to_str(match->rpm_code, names_rrenum_matchcode, "Unknown"),
657 proto_tree_add_text(opt_tree, NullTVB,
658 off + offsetof(struct rr_pco_match, rpm_len),
659 sizeof(match->rpm_len), "OpLength: %u (%u octets)",
660 match->rpm_len, match->rpm_len * 8);
661 proto_tree_add_text(opt_tree, NullTVB,
662 off + offsetof(struct rr_pco_match, rpm_ordinal),
663 sizeof(match->rpm_ordinal), "Ordinal: %u", match->rpm_ordinal);
664 proto_tree_add_text(opt_tree, NullTVB,
665 off + offsetof(struct rr_pco_match, rpm_matchlen),
666 sizeof(match->rpm_matchlen), "MatchLen: %u", match->rpm_matchlen);
667 proto_tree_add_text(opt_tree, NullTVB,
668 off + offsetof(struct rr_pco_match, rpm_minlen),
669 sizeof(match->rpm_minlen), "MinLen: %u", match->rpm_minlen);
670 proto_tree_add_text(opt_tree, NullTVB,
671 off + offsetof(struct rr_pco_match, rpm_maxlen),
672 sizeof(match->rpm_maxlen), "MaxLen: %u", match->rpm_maxlen);
673 proto_tree_add_text(opt_tree, NullTVB,
674 off + offsetof(struct rr_pco_match, rpm_prefix),
675 sizeof(match->rpm_prefix), "MatchPrefix: %s",
676 ip6_to_str(&match->rpm_prefix));
678 off += sizeof(*match);
679 use = (struct rr_pco_use *)&pd[off];
680 for (l = match->rpm_len * 8 - sizeof(*match);
681 l >= sizeof(*use); l -= sizeof(*use), off += sizeof(*use)) {
682 tf = proto_tree_add_text(tree, NullTVB, off, sizeof(*use),
683 "Use-Prefix: %s/%u (keep %u)", ip6_to_str(&use->rpu_prefix),
684 use->rpu_uselen, use->rpu_keeplen);
685 opt_tree = proto_item_add_subtree(tf, ett_icmpv6opt);
686 proto_tree_add_text(opt_tree, NullTVB,
687 off + offsetof(struct rr_pco_use, rpu_uselen),
688 sizeof(use->rpu_uselen), "UseLen: %u", use->rpu_uselen);
689 proto_tree_add_text(opt_tree, NullTVB,
690 off + offsetof(struct rr_pco_use, rpu_keeplen),
691 sizeof(use->rpu_keeplen), "KeepLen: %u", use->rpu_keeplen);
692 tf = proto_tree_add_text(opt_tree, NullTVB,
693 flagoff = off + offsetof(struct rr_pco_use, rpu_ramask),
694 sizeof(use->rpu_ramask), "FlagMask: 0x%x", use->rpu_ramask);
695 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
696 proto_tree_add_text(field_tree, NullTVB, flagoff, 1, "%s",
697 decode_boolean_bitfield(pd[flagoff],
698 ICMP6_RR_PCOUSE_RAFLAGS_ONLINK, 8,
699 "Onlink", "Not onlink"));
700 proto_tree_add_text(field_tree, NullTVB, flagoff, 1, "%s",
701 decode_boolean_bitfield(pd[flagoff],
702 ICMP6_RR_PCOUSE_RAFLAGS_AUTO, 8,
703 "Auto", "Not auto"));
704 tf = proto_tree_add_text(opt_tree, NullTVB,
705 flagoff = off + offsetof(struct rr_pco_use, rpu_raflags),
706 sizeof(use->rpu_raflags), "RAFlags: 0x%x", use->rpu_raflags);
707 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
708 proto_tree_add_text(field_tree, NullTVB, flagoff, 1, "%s",
709 decode_boolean_bitfield(pd[flagoff],
710 ICMP6_RR_PCOUSE_RAFLAGS_ONLINK, 8,
711 "Onlink", "Not onlink"));
712 proto_tree_add_text(field_tree, NullTVB, flagoff, 1, "%s",
713 decode_boolean_bitfield(pd[flagoff],
714 ICMP6_RR_PCOUSE_RAFLAGS_AUTO, 8, "Auto", "Not auto"));
715 if (pntohl(&use->rpu_vltime) == 0xffffffff)
716 proto_tree_add_text(opt_tree, NullTVB,
717 off + offsetof(struct rr_pco_use, rpu_vltime),
718 sizeof(use->rpu_vltime), "Valid Lifetime: infinity");
720 proto_tree_add_text(opt_tree, NullTVB,
721 off + offsetof(struct rr_pco_use, rpu_vltime),
722 sizeof(use->rpu_vltime), "Valid Lifetime: %u",
723 pntohl(&use->rpu_vltime));
724 if (pntohl(&use->rpu_pltime) == 0xffffffff)
725 proto_tree_add_text(opt_tree, NullTVB,
726 off + offsetof(struct rr_pco_use, rpu_pltime),
727 sizeof(use->rpu_pltime), "Preferred Lifetime: infinity");
729 proto_tree_add_text(opt_tree, NullTVB,
730 off + offsetof(struct rr_pco_use, rpu_pltime),
731 sizeof(use->rpu_pltime), "Preferred Lifetime: %u",
732 pntohl(&use->rpu_pltime));
733 tf = proto_tree_add_text(opt_tree, NullTVB,
734 flagoff = off + offsetof(struct rr_pco_use, rpu_flags),
735 sizeof(use->rpu_flags), "Flags: 0x%08x",
736 pntohl(&use->rpu_flags));
737 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
738 proto_tree_add_text(field_tree, NullTVB, flagoff, 4, "%s",
739 decode_boolean_bitfield(pd[flagoff],
740 ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, 32,
741 "Decrement valid lifetime", "No decrement valid lifetime"));
742 proto_tree_add_text(field_tree, NullTVB, flagoff, 4, "%s",
743 decode_boolean_bitfield(pd[flagoff],
744 ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, 32,
745 "Decrement preferred lifetime",
746 "No decrement preferred lifetime"));
747 proto_tree_add_text(opt_tree, NullTVB,
748 off + offsetof(struct rr_pco_use, rpu_prefix),
749 sizeof(use->rpu_prefix), "UsePrefix: %s",
750 ip6_to_str(&use->rpu_prefix));
757 dissect_icmpv6(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
759 proto_tree *icmp6_tree, *field_tree;
760 proto_item *ti, *tf = NULL;
761 struct icmp6_hdr *dp;
762 struct icmp6_nodeinfo *ni = NULL;
763 char *codename, *typename;
764 char *colcodename, *coltypename;
766 guint length, reported_length;
769 guint16 cksum, computed_cksum;
771 dp = (struct icmp6_hdr *)&pd[offset];
772 codename = typename = colcodename = coltypename = "Unknown";
774 switch (dp->icmp6_type) {
775 case ICMP6_DST_UNREACH:
776 typename = coltypename = "Unreachable";
777 switch (dp->icmp6_code) {
778 case ICMP6_DST_UNREACH_NOROUTE:
779 codename = colcodename = "Route unreachable";
781 case ICMP6_DST_UNREACH_ADMIN:
782 codename = colcodename = "Administratively prohibited";
784 case ICMP6_DST_UNREACH_NOTNEIGHBOR:
785 codename = colcodename = "Not a neighbor";
787 case ICMP6_DST_UNREACH_ADDR:
788 codename = colcodename = "Address unreachable";
790 case ICMP6_DST_UNREACH_NOPORT:
791 codename = colcodename = "Port unreachable";
795 case ICMP6_PACKET_TOO_BIG:
796 typename = coltypename = "Too big";
797 codename = colcodename = NULL;
799 case ICMP6_TIME_EXCEEDED:
800 typename = coltypename = "Time exceeded";
801 switch (dp->icmp6_code) {
802 case ICMP6_TIME_EXCEED_TRANSIT:
803 codename = colcodename = "In-transit";
805 case ICMP6_TIME_EXCEED_REASSEMBLY:
806 codename = colcodename = "Reassembly";
810 case ICMP6_PARAM_PROB:
811 typename = coltypename = "Parameter problem";
812 switch (dp->icmp6_code) {
813 case ICMP6_PARAMPROB_HEADER:
814 codename = colcodename = "Header";
816 case ICMP6_PARAMPROB_NEXTHEADER:
817 codename = colcodename = "Next header";
819 case ICMP6_PARAMPROB_OPTION:
820 codename = colcodename = "Option";
824 case ICMP6_ECHO_REQUEST:
825 typename = coltypename = "Echo request";
826 codename = colcodename = NULL;
828 case ICMP6_ECHO_REPLY:
829 typename = coltypename = "Echo reply";
830 codename = colcodename = NULL;
832 case ICMP6_MEMBERSHIP_QUERY:
833 typename = coltypename = "Multicast listener query";
834 codename = colcodename = NULL;
836 case ICMP6_MEMBERSHIP_REPORT:
837 typename = coltypename = "Multicast listener report";
838 codename = colcodename = NULL;
840 case ICMP6_MEMBERSHIP_REDUCTION:
841 typename = coltypename = "Multicast listener done";
842 codename = colcodename = NULL;
844 case ND_ROUTER_SOLICIT:
845 typename = coltypename = "Router solicitation";
846 codename = colcodename = NULL;
847 len = sizeof(struct nd_router_solicit);
849 case ND_ROUTER_ADVERT:
850 typename = coltypename = "Router advertisement";
851 codename = colcodename = NULL;
852 len = sizeof(struct nd_router_advert);
854 case ND_NEIGHBOR_SOLICIT:
855 typename = coltypename = "Neighbor solicitation";
856 codename = colcodename = NULL;
857 len = sizeof(struct nd_neighbor_solicit);
859 case ND_NEIGHBOR_ADVERT:
860 typename = coltypename = "Neighbor advertisement";
861 codename = colcodename = NULL;
862 len = sizeof(struct nd_neighbor_advert);
865 typename = coltypename = "Redirect";
866 codename = colcodename = NULL;
867 len = sizeof(struct nd_redirect);
869 case ICMP6_ROUTER_RENUMBERING:
870 typename = coltypename = "Router renumbering";
871 switch (dp->icmp6_code) {
872 case ICMP6_ROUTER_RENUMBERING_COMMAND:
873 codename = colcodename = "Command";
875 case ICMP6_ROUTER_RENUMBERING_RESULT:
876 codename = colcodename = "Result";
878 case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
879 codename = colcodename = "Sequence number reset";
882 len = sizeof(struct icmp6_router_renum);
886 ni = (struct icmp6_nodeinfo *)dp;
887 if (ni->ni_type == ICMP6_NI_QUERY) {
888 typename = coltypename = "Node information query";
889 switch (ni->ni_code) {
890 case ICMP6_NI_SUBJ_IPV6:
891 codename = "Query subject = IPv6 addresses";
893 case ICMP6_NI_SUBJ_FQDN:
894 if (IS_DATA_IN_FRAME(offset + sizeof(*ni)))
895 codename = "Query subject = DNS name";
897 codename = "Query subject = empty";
899 case ICMP6_NI_SUBJ_IPV4:
900 codename = "Query subject = IPv4 addresses";
904 typename = coltypename = "Node information reply";
905 switch (ni->ni_code) {
906 case ICMP6_NI_SUCCESS:
907 codename = "Successful";
909 case ICMP6_NI_REFUSED:
910 codename = "Refused";
912 case ICMP6_NI_UNKNOWN:
913 codename = "Unknown query type";
917 colcodename = val_to_str(pntohs(&ni->ni_qtype), names_nodeinfo_qtype,
919 len = sizeof(struct icmp6_nodeinfo);
923 if (check_col(fd, COL_PROTOCOL))
924 col_set_str(fd, COL_PROTOCOL, "ICMPv6");
925 if (check_col(fd, COL_INFO)) {
926 char typebuf[256], codebuf[256];
928 if (coltypename && strcmp(coltypename, "Unknown") == 0) {
929 snprintf(typebuf, sizeof(typebuf), "Unknown (0x%02x)",
931 coltypename = typebuf;
933 if (colcodename && strcmp(colcodename, "Unknown") == 0) {
934 snprintf(codebuf, sizeof(codebuf), "Unknown (0x%02x)",
936 colcodename = codebuf;
939 col_add_fstr(fd, COL_INFO, "%s (%s)", coltypename, colcodename);
941 col_add_fstr(fd, COL_INFO, "%s", coltypename);
946 /* !!! specify length */
947 ti = proto_tree_add_item(tree, proto_icmpv6, NullTVB, offset, len, FALSE);
948 icmp6_tree = proto_item_add_subtree(ti, ett_icmpv6);
950 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_type, NullTVB,
951 offset + offsetof(struct icmp6_hdr, icmp6_type), 1,
953 "Type: 0x%02x (%s)", dp->icmp6_type, typename);
955 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_code, NullTVB,
956 offset + offsetof(struct icmp6_hdr, icmp6_code), 1,
958 "Code: 0x%02x (%s)", dp->icmp6_code, codename);
960 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_code, NullTVB,
961 offset + offsetof(struct icmp6_hdr, icmp6_code), 1,
963 "Code: 0x%02x", dp->icmp6_code);
965 cksum = (guint16)htons(dp->icmp6_cksum);
966 length = pi.captured_len - offset;
967 reported_length = pi.len - offset;
968 if (!pi.fragmented && length >= reported_length) {
969 /* The packet isn't part of a fragmented datagram and isn't
970 truncated, so we can checksum it. */
972 /* Set up the fields of the pseudo-header. */
973 cksum_vec[0].ptr = pi.src.data;
974 cksum_vec[0].len = pi.src.len;
975 cksum_vec[1].ptr = pi.dst.data;
976 cksum_vec[1].len = pi.dst.len;
977 cksum_vec[2].ptr = (const guint8 *)&phdr;
978 phdr[0] = htonl(reported_length);
979 phdr[1] = htonl(IP_PROTO_ICMPV6);
980 cksum_vec[2].len = 8;
981 cksum_vec[3].ptr = &pd[offset];
982 cksum_vec[3].len = reported_length;
983 computed_cksum = in_cksum(cksum_vec, 4);
984 if (computed_cksum == 0) {
985 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_checksum,
987 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
989 "Checksum: 0x%04x (correct)", cksum);
991 proto_tree_add_item_hidden(icmp6_tree, hf_icmpv6_checksum_bad,
993 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
995 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_checksum,
997 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
999 "Checksum: 0x%04x (incorrect, should be 0x%04x)",
1000 cksum, in_cksum_shouldbe(cksum, computed_cksum));
1003 proto_tree_add_uint(icmp6_tree, hf_icmpv6_checksum, NullTVB,
1004 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1009 switch (dp->icmp6_type) {
1010 case ICMP6_DST_UNREACH:
1011 case ICMP6_TIME_EXCEEDED:
1012 /* tiny sanity check */
1013 if ((pd[offset + sizeof(*dp)] & 0xf0) == 0x60) {
1014 dissect_ipv6(pd, offset + sizeof(*dp), fd, icmp6_tree);
1016 old_dissect_data(pd, offset + sizeof(*dp), fd, icmp6_tree);
1019 case ICMP6_PACKET_TOO_BIG:
1020 proto_tree_add_text(icmp6_tree, NullTVB,
1021 offset + offsetof(struct icmp6_hdr, icmp6_mtu), 4,
1022 "MTU: %d", pntohl(&dp->icmp6_mtu));
1023 /* tiny sanity check */
1024 if ((pd[offset + sizeof(*dp)] & 0xf0) == 0x60) {
1025 dissect_ipv6(pd, offset + sizeof(*dp), fd, icmp6_tree);
1027 old_dissect_data(pd, offset + sizeof(*dp), fd, icmp6_tree);
1030 case ICMP6_PARAM_PROB:
1031 proto_tree_add_text(icmp6_tree, NullTVB,
1032 offset + offsetof(struct icmp6_hdr, icmp6_pptr), 4,
1033 "Problem pointer: 0x%04x", pntohl(&dp->icmp6_pptr));
1034 /* tiny sanity check */
1035 if ((pd[offset + sizeof(*dp)] & 0xf0) == 0x60) {
1036 dissect_ipv6(pd, offset + sizeof(*dp), fd, icmp6_tree);
1038 old_dissect_data(pd, offset + sizeof(*dp), fd, icmp6_tree);
1041 case ICMP6_ECHO_REQUEST:
1042 case ICMP6_ECHO_REPLY:
1043 proto_tree_add_text(icmp6_tree, NullTVB,
1044 offset + offsetof(struct icmp6_hdr, icmp6_id), 2,
1045 "ID: 0x%04x", (guint16)ntohs(dp->icmp6_id));
1046 proto_tree_add_text(icmp6_tree, NullTVB,
1047 offset + offsetof(struct icmp6_hdr, icmp6_seq), 2,
1048 "Sequence: 0x%04x", (guint16)ntohs(dp->icmp6_seq));
1049 old_dissect_data(pd, offset + sizeof(*dp), fd, icmp6_tree);
1051 case ICMP6_MEMBERSHIP_QUERY:
1052 case ICMP6_MEMBERSHIP_REPORT:
1053 case ICMP6_MEMBERSHIP_REDUCTION:
1054 proto_tree_add_text(icmp6_tree, NullTVB,
1055 offset + offsetof(struct icmp6_hdr, icmp6_maxdelay), 2,
1056 "Maximum response delay: %d",
1057 (guint16)ntohs(dp->icmp6_maxdelay));
1058 proto_tree_add_text(icmp6_tree, NullTVB, offset + sizeof(*dp), 16,
1059 "Multicast Address: %s",
1060 ip6_to_str((struct e_in6_addr *)(dp + 1)));
1062 case ND_ROUTER_SOLICIT:
1063 dissect_icmpv6opt(pd, offset + sizeof(*dp), fd, icmp6_tree);
1065 case ND_ROUTER_ADVERT:
1067 struct nd_router_advert *ra = (struct nd_router_advert *)dp;
1071 proto_tree_add_text(icmp6_tree, NullTVB,
1072 offset + offsetof(struct nd_router_advert, nd_ra_curhoplimit),
1073 1, "Cur hop limit: %d", ra->nd_ra_curhoplimit);
1075 flagoff = offset + offsetof(struct nd_router_advert, nd_ra_flags_reserved);
1076 ra_flags = pntohl(&pd[flagoff]);
1077 tf = proto_tree_add_text(icmp6_tree, NullTVB, flagoff, 4, "Flags: 0x%08x", ra_flags);
1078 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1079 proto_tree_add_text(field_tree, NullTVB, flagoff, 4, "%s",
1080 decode_boolean_bitfield(ra_flags,
1081 0x80000000, 32, "Managed", "Not managed"));
1082 proto_tree_add_text(field_tree, NullTVB, flagoff, 4, "%s",
1083 decode_boolean_bitfield(ra_flags,
1084 0x40000000, 32, "Other", "Not other"));
1085 /* BT INSERT BEGIN */
1086 proto_tree_add_text(field_tree, NullTVB, flagoff, 4, "%s",
1087 decode_boolean_bitfield(ra_flags,
1088 0x20000000, 32, "Home Agent", "Not Home Agent"));
1090 proto_tree_add_text(icmp6_tree, NullTVB,
1091 offset + offsetof(struct nd_router_advert, nd_ra_router_lifetime),
1092 2, "Router lifetime: %d",
1093 (guint16)ntohs(ra->nd_ra_router_lifetime));
1094 proto_tree_add_text(icmp6_tree, NullTVB,
1095 offset + offsetof(struct nd_router_advert, nd_ra_reachable), 4,
1096 "Reachable time: %d", pntohl(&ra->nd_ra_reachable));
1097 proto_tree_add_text(icmp6_tree, NullTVB,
1098 offset + offsetof(struct nd_router_advert, nd_ra_retransmit), 4,
1099 "Retrans time: %d", pntohl(&ra->nd_ra_retransmit));
1100 dissect_icmpv6opt(pd, offset + sizeof(struct nd_router_advert), fd, icmp6_tree);
1103 case ND_NEIGHBOR_SOLICIT:
1105 struct nd_neighbor_solicit *ns = (struct nd_neighbor_solicit *)dp;
1107 proto_tree_add_text(icmp6_tree, NullTVB,
1108 offset + offsetof(struct nd_neighbor_solicit, nd_ns_target), 16,
1111 get_hostname6(&ns->nd_ns_target),
1115 ip6_to_str(&ns->nd_ns_target));
1117 dissect_icmpv6opt(pd, offset + sizeof(*ns), fd, icmp6_tree);
1120 case ND_NEIGHBOR_ADVERT:
1122 int flagoff, targetoff;
1124 struct e_in6_addr *na_target_p;
1126 flagoff = offset + offsetof(struct nd_neighbor_advert, nd_na_flags_reserved);
1127 na_flags = pntohl(&pd[flagoff]);
1129 tf = proto_tree_add_text(icmp6_tree, NullTVB, flagoff, 4, "Flags: 0x%08x", na_flags);
1130 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1131 proto_tree_add_text(field_tree, NullTVB, flagoff, 4, "%s",
1132 decode_boolean_bitfield(na_flags,
1133 ND_NA_FLAG_ROUTER, 32, "Router", "Not router"));
1134 proto_tree_add_text(field_tree, NullTVB, flagoff, 4, "%s",
1135 decode_boolean_bitfield(na_flags,
1136 ND_NA_FLAG_SOLICITED, 32, "Solicited", "Not adverted"));
1137 proto_tree_add_text(field_tree, NullTVB, flagoff, 4, "%s",
1138 decode_boolean_bitfield(na_flags,
1139 ND_NA_FLAG_OVERRIDE, 32, "Override", "Not override"));
1141 targetoff = offset + offsetof(struct nd_neighbor_advert, nd_na_target);
1142 na_target_p = (struct e_in6_addr*) &pd[targetoff];
1143 proto_tree_add_text(icmp6_tree, NullTVB, targetoff, 16,
1146 get_hostname6(na_target_p),
1150 ip6_to_str(na_target_p));
1152 dissect_icmpv6opt(pd, offset + sizeof(struct nd_neighbor_advert), fd, icmp6_tree);
1157 struct nd_redirect *rd = (struct nd_redirect *)dp;
1159 proto_tree_add_text(icmp6_tree, NullTVB,
1160 offset + offsetof(struct nd_redirect, nd_rd_target), 16,
1163 get_hostname6(&rd->nd_rd_target),
1167 ip6_to_str(&rd->nd_rd_target));
1169 proto_tree_add_text(icmp6_tree, NullTVB,
1170 offset + offsetof(struct nd_redirect, nd_rd_dst), 16,
1172 "Destination: %s (%s)",
1173 get_hostname6(&rd->nd_rd_dst),
1177 ip6_to_str(&rd->nd_rd_dst));
1179 dissect_icmpv6opt(pd, offset + sizeof(*rd), fd, icmp6_tree);
1182 case ICMP6_ROUTER_RENUMBERING:
1183 dissect_rrenum(pd, offset, fd, icmp6_tree);
1185 case ICMP6_NI_QUERY:
1186 case ICMP6_NI_REPLY:
1187 ni = (struct icmp6_nodeinfo *)dp;
1188 proto_tree_add_text(icmp6_tree, NullTVB,
1189 offset + offsetof(struct icmp6_nodeinfo, ni_qtype),
1190 sizeof(ni->ni_qtype),
1191 "Query type: 0x%04x (%s)", pntohs(&ni->ni_qtype),
1192 val_to_str(pntohs(&ni->ni_qtype), names_nodeinfo_qtype,
1194 dissect_nodeinfo(pd, offset, fd, icmp6_tree);
1197 old_dissect_data(pd, offset + sizeof(*dp), fd, tree);
1204 proto_register_icmpv6(void)
1206 static hf_register_info hf[] = {
1208 { "Type", "icmpv6.type", FT_UINT8, BASE_HEX, NULL, 0x0,
1211 { "Code", "icmpv6.code", FT_UINT8, BASE_HEX, NULL, 0x0,
1213 { &hf_icmpv6_checksum,
1214 { "Checksum", "icmpv6.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
1216 { &hf_icmpv6_checksum_bad,
1217 { "Bad Checksum", "icmpv6.checksum_bad", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1220 static gint *ett[] = {
1225 &ett_nodeinfo_subject4,
1226 &ett_nodeinfo_subject6,
1227 &ett_nodeinfo_node4,
1228 &ett_nodeinfo_node6,
1229 &ett_nodeinfo_nodebitmap,
1230 &ett_nodeinfo_nodedns,
1233 proto_icmpv6 = proto_register_protocol("Internet Control Message Protocol v6",
1234 "ICMPv6", "icmpv6");
1235 proto_register_field_array(proto_icmpv6, hf, array_length(hf));
1236 proto_register_subtree_array(ett, array_length(ett));
1240 proto_reg_handoff_icmpv6(void)
1242 old_dissector_add("ip.proto", IP_PROTO_ICMPV6, dissect_icmpv6, proto_icmpv6);