2 * Routines for ICMPv6 packet disassembly
4 * $Id: packet-icmpv6.c,v 1.36 2001/01/23 02:49:55 gerald 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;
70 static gint ett_icmpv6 = -1;
71 static gint ett_icmpv6opt = -1;
72 static gint ett_icmpv6flag = -1;
73 static gint ett_nodeinfo_flag = -1;
74 static gint ett_nodeinfo_subject4 = -1;
75 static gint ett_nodeinfo_subject6 = -1;
76 static gint ett_nodeinfo_node4 = -1;
77 static gint ett_nodeinfo_node6 = -1;
78 static gint ett_nodeinfo_nodebitmap = -1;
79 static gint ett_nodeinfo_nodedns = -1;
81 static const value_string names_nodeinfo_qtype[] = {
82 { NI_QTYPE_NOOP, "NOOP" },
83 { NI_QTYPE_SUPTYPES, "Supported query types" },
84 { NI_QTYPE_DNSNAME, "DNS name" },
85 { NI_QTYPE_NODEADDR, "Node addresses" },
86 { NI_QTYPE_IPV4ADDR, "IPv4 node addresses" },
90 static const value_string names_rrenum_matchcode[] = {
91 { RPM_PCO_ADD, "Add" },
92 { RPM_PCO_CHANGE, "Change" },
93 { RPM_PCO_SETGLOBAL, "Set Global" },
98 dissect_icmpv6opt(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
100 proto_tree *icmp6opt_tree, *field_tree;
102 struct nd_opt_hdr *opt;
110 if (!IS_DATA_IN_FRAME(offset))
113 opt = (struct nd_opt_hdr *)&pd[offset];
114 len = opt->nd_opt_len << 3;
116 /* !!! specify length */
117 ti = proto_tree_add_text(tree, NullTVB, offset, len, "ICMPv6 options");
118 icmp6opt_tree = proto_item_add_subtree(ti, ett_icmpv6opt);
120 switch (opt->nd_opt_type) {
121 case ND_OPT_SOURCE_LINKADDR:
122 typename = "Source link-layer address";
124 case ND_OPT_TARGET_LINKADDR:
125 typename = "Target link-layer address";
127 case ND_OPT_PREFIX_INFORMATION:
128 typename = "Prefix information";
130 case ND_OPT_REDIRECTED_HEADER:
131 typename = "Redirected header";
136 case ND_OPT_ADVERTISEMENT_INTERVAL:
137 typename = "Advertisement Interval";
139 case ND_OPT_HOME_AGENT_INFORMATION:
140 typename = "Home Agent Information";
144 typename = "Unknown";
148 proto_tree_add_text(icmp6opt_tree, NullTVB,
149 offset + offsetof(struct nd_opt_hdr, nd_opt_type), 1,
150 "Type: 0x%02x (%s)", opt->nd_opt_type, typename);
151 proto_tree_add_text(icmp6opt_tree, NullTVB,
152 offset + offsetof(struct nd_opt_hdr, nd_opt_len), 1,
153 "Length: %d bytes (0x%02x)", opt->nd_opt_len << 3, opt->nd_opt_len);
156 switch (opt->nd_opt_type) {
157 case ND_OPT_SOURCE_LINKADDR:
158 case ND_OPT_TARGET_LINKADDR:
163 len = (opt->nd_opt_len << 3) - sizeof(*opt);
164 t = (char *)malloc(len * 3);
165 memset(t, 0, len * 3);
166 p = &pd[offset + sizeof(*opt)];
167 for (i = 0; i < len; i++) {
170 sprintf(&t[i * 3], "%02x", p[i] & 0xff);
172 proto_tree_add_text(icmp6opt_tree, NullTVB,
173 offset + sizeof(*opt), len, "Link-layer address: %s", t);
176 case ND_OPT_PREFIX_INFORMATION:
178 struct nd_opt_prefix_info *pi = (struct nd_opt_prefix_info *)opt;
180 proto_tree_add_text(icmp6opt_tree, NullTVB,
181 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_prefix_len),
182 1, "Prefix length: %d", pi->nd_opt_pi_prefix_len);
184 flagoff = offsetof(struct nd_opt_prefix_info, nd_opt_pi_flags_reserved);
185 tf = proto_tree_add_text(icmp6opt_tree, NullTVB, flagoff, 1, "Flags: 0x%02x",
186 pntohl(&pi->nd_opt_pi_flags_reserved));
187 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
188 proto_tree_add_text(field_tree, NullTVB, flagoff, 1, "%s",
189 decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
190 0x80, 8, "Onlink", "Not onlink"));
191 proto_tree_add_text(field_tree, NullTVB, flagoff, 1, "%s",
192 decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
193 0x40, 8, "Auto", "Not auto"));
194 /* BT INSERT BEGIN */
195 proto_tree_add_text(field_tree, NullTVB, flagoff, 1, "%s",
196 decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
197 0x20, 8, "Router Address", "Not router address"));
199 proto_tree_add_text(icmp6opt_tree, NullTVB,
200 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_valid_time),
201 4, "Valid lifetime: 0x%08x",
202 pntohl(&pi->nd_opt_pi_valid_time));
203 proto_tree_add_text(icmp6opt_tree, NullTVB,
204 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_preferred_time),
205 4, "Preferred lifetime: 0x%08x",
206 pntohl(&pi->nd_opt_pi_preferred_time));
207 proto_tree_add_text(icmp6opt_tree, NullTVB,
208 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_prefix),
209 16, "Prefix: %s", ip6_to_str(&pi->nd_opt_pi_prefix));
212 case ND_OPT_REDIRECTED_HEADER:
213 proto_tree_add_text(icmp6opt_tree, NullTVB,
214 offset + 8, (opt->nd_opt_len << 3) - 8, "Redirected packet");
215 /* tiny sanity check */
216 if ((pd[offset + 8] & 0xf0) == 0x60)
217 dissect_ipv6(pd, offset + 8, fd, icmp6opt_tree);
219 old_dissect_data(pd, offset + 8, fd, icmp6opt_tree);
223 struct nd_opt_mtu *pi = (struct nd_opt_mtu *)opt;
224 proto_tree_add_text(icmp6opt_tree, NullTVB,
225 offset + offsetof(struct nd_opt_mtu, nd_opt_mtu_mtu), 4,
226 "MTU: %d", pntohl(&pi->nd_opt_mtu_mtu));
229 /* BT INSERT BEGIN */
230 case ND_OPT_ADVERTISEMENT_INTERVAL:
232 struct nd_opt_adv_int *pi = (struct nd_opt_adv_int *)opt;
233 proto_tree_add_text(icmp6opt_tree, NullTVB,
234 offset + offsetof(struct nd_opt_adv_int, nd_opt_adv_int_advint), 4,
235 "Advertisement Interval: %d", pntohl(&pi->nd_opt_adv_int_advint));
238 case ND_OPT_HOME_AGENT_INFORMATION:
240 struct nd_opt_ha_info *pi = (struct nd_opt_ha_info *)opt;
241 proto_tree_add_text(icmp6opt_tree, NullTVB,
242 offset + offsetof(struct nd_opt_ha_info, nd_opt_ha_info_ha_pref),
243 2, "Home Agent Preference: %d",
244 pntohs(&pi->nd_opt_ha_info_ha_pref));
245 proto_tree_add_text(icmp6opt_tree, NullTVB,
246 offset + offsetof(struct nd_opt_ha_info, nd_opt_ha_info_ha_life),
247 2, "Home Agent Lifetime: %d",
248 pntohs(&pi->nd_opt_ha_info_ha_life));
254 if (opt->nd_opt_len == 0) {
255 proto_tree_add_text(icmp6opt_tree, NullTVB,
256 offset + offsetof(struct nd_opt_hdr, nd_opt_len), 1,
257 "Invalid option length: %d",
262 offset += (opt->nd_opt_len << 3);
267 * draft-ietf-ipngwg-icmp-name-lookups-06.txt
268 * Note that the packet format was changed several times in the past.
272 bitrange0(v, s, buf, buflen)
292 ep = buf + buflen - 1;
293 memset(buf, 0, buflen);
296 /* shift till we have 0x01 */
297 if ((v & 0x01) == 0) {
300 v >>= 4; off += 4; continue;
302 v >>= 3; off += 3; continue;
303 case 0x04: case 0x0c:
304 v >>= 2; off += 2; continue;
306 v >>= 1; off += 1; continue;
310 /* we have 0x01 with us */
311 for (i = 0; i < 32 - off; i++) {
312 if ((v & (0x01 << i)) == 0)
316 l = snprintf(p, ep - p, ",%d", s + off);
318 l = snprintf(p, ep - p, ",%d-%d", s + off,
332 bitrange(u_char *p, int l, int s)
334 static char buf[1024];
338 memset(buf, 0, sizeof(buf));
340 eq = buf + sizeof(buf) - 1;
341 for (i = 0; i < l; i++) {
342 if (bitrange0(pntohl(p + i * 4), s + i * 4, q, eq - q) == NULL) {
343 if (q != buf && q + 5 < buf + sizeof(buf))
344 strncpy(q, ",...", 5);
353 dissect_nodeinfo(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
355 proto_tree *field_tree;
357 struct icmp6_nodeinfo *ni;
362 char dname[MAXDNAME];
364 ni = (struct icmp6_nodeinfo *)&pd[offset];
367 flags = pntohs(&ni->ni_flags);
368 tf = proto_tree_add_text(tree, NullTVB,
369 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
370 sizeof(ni->ni_flags), "Flags: 0x%04x", flags);
371 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_flag);
372 switch (pntohs(&ni->ni_qtype)) {
373 case NI_QTYPE_SUPTYPES:
374 if (ni->ni_type == ICMP6_NI_QUERY) {
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_SUPTYPE_FLAG_COMPRESS, sizeof(flags) * 8,
379 "Compressed reply supported",
380 "No compressed reply support"));
382 proto_tree_add_text(field_tree, NullTVB,
383 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
384 sizeof(ni->ni_flags), "%s",
385 decode_boolean_bitfield(flags, NI_SUPTYPE_FLAG_COMPRESS, sizeof(flags) * 8,
386 "Compressed", "Not compressed"));
389 case NI_QTYPE_DNSNAME:
390 if (ni->ni_type == ICMP6_NI_REPLY) {
391 proto_tree_add_text(field_tree, NullTVB,
392 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
393 sizeof(ni->ni_flags), "%s",
394 decode_boolean_bitfield(flags, NI_FQDN_FLAG_VALIDTTL, sizeof(flags) * 8,
395 "Valid TTL field", "Meaningless TTL field"));
398 case NI_QTYPE_NODEADDR:
399 proto_tree_add_text(field_tree, NullTVB,
400 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
401 sizeof(ni->ni_flags), "%s",
402 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_GLOBAL, sizeof(flags) * 8,
404 "Not global address"));
405 proto_tree_add_text(field_tree, NullTVB,
406 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
407 sizeof(ni->ni_flags), "%s",
408 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_SITELOCAL, sizeof(flags) * 8,
409 "Site-local address",
410 "Not site-local address"));
411 proto_tree_add_text(field_tree, NullTVB,
412 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
413 sizeof(ni->ni_flags), "%s",
414 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_LINKLOCAL, sizeof(flags) * 8,
415 "Link-local address",
416 "Not link-local address"));
417 proto_tree_add_text(field_tree, NullTVB,
418 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
419 sizeof(ni->ni_flags), "%s",
420 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_COMPAT, sizeof(flags) * 8,
421 "IPv4 compatible/mapped address",
422 "Not IPv4 compatible/mapped address"));
424 case NI_QTYPE_IPV4ADDR:
425 proto_tree_add_text(field_tree, NullTVB,
426 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
427 sizeof(ni->ni_flags), "%s",
428 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_ALL, sizeof(flags) * 8,
429 "All unicast address",
430 "Unicast addresses on the queried interface"));
431 proto_tree_add_text(field_tree, NullTVB,
432 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
433 sizeof(ni->ni_flags), "%s",
434 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_TRUNCATE, sizeof(flags) * 8,
435 "Truncated", "Not truncated"));
440 proto_tree_add_text(tree, NullTVB,
441 offset + offsetof(struct icmp6_nodeinfo, icmp6_ni_nonce[0]),
442 sizeof(ni->icmp6_ni_nonce), "Nonce: 0x%08x%08x",
443 pntohl(&ni->icmp6_ni_nonce[0]), pntohl(&ni->icmp6_ni_nonce[4]));
445 /* offset for "the rest of data" */
449 if (!IS_DATA_IN_FRAME(offset + sizeof(*ni)))
451 if (ni->ni_type == ICMP6_NI_QUERY) {
452 switch (ni->ni_code) {
453 case ICMP6_NI_SUBJ_IPV6:
454 n = pi.captured_len - (offset + sizeof(*ni));
455 n /= sizeof(struct e_in6_addr);
456 tf = proto_tree_add_text(tree, NullTVB,
457 offset + sizeof(*ni), END_OF_FRAME, "IPv6 subject addresses");
458 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_subject6);
459 p = (u_char *)(ni + 1);
460 for (i = 0; i < n; i++) {
461 proto_tree_add_text(field_tree, NullTVB,
462 p - pd, sizeof(struct e_in6_addr),
463 "%s", ip6_to_str((struct e_in6_addr *)p));
464 p += sizeof(struct e_in6_addr);
466 off = pi.captured_len - offset;
468 case ICMP6_NI_SUBJ_FQDN:
469 l = get_dns_name(pd, offset + sizeof(*ni), offset + sizeof(*ni),
470 dname, sizeof(dname));
471 if (IS_DATA_IN_FRAME(offset + sizeof(*ni) + l) &&
472 pd[offset + sizeof(*ni) + l] == 0) {
474 proto_tree_add_text(tree, NullTVB, offset + sizeof(*ni), l,
475 "DNS label: %s (truncated)", dname);
477 proto_tree_add_text(tree, NullTVB, offset + sizeof(*ni), l,
478 "DNS label: %s", dname);
480 off = offset + sizeof(*ni) + l;
482 case ICMP6_NI_SUBJ_IPV4:
483 n = pi.captured_len - (offset + sizeof(*ni));
484 n /= sizeof(guint32);
485 tf = proto_tree_add_text(tree, NullTVB,
486 offset + sizeof(*ni), END_OF_FRAME, "IPv4 subject addresses");
487 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_subject4);
488 p = (u_char *)(ni + 1);
489 for (i = 0; i < n; i++) {
490 proto_tree_add_text(field_tree, NullTVB,
491 p - pd, sizeof(guint32), "%s", ip_to_str(p));
492 p += sizeof(guint32);
494 off = pi.captured_len - offset;
498 switch (pntohs(&ni->ni_qtype)) {
501 case NI_QTYPE_SUPTYPES:
502 p = (u_char *)(ni + 1);
503 tf = proto_tree_add_text(tree, NullTVB,
504 offset + sizeof(*ni), END_OF_FRAME,
505 "Supported type bitmap%s",
506 (flags & 0x0001) ? ", compressed" : "");
507 field_tree = proto_item_add_subtree(tf,
508 ett_nodeinfo_nodebitmap);
510 while (IS_DATA_IN_FRAME(p - pd)) {
511 if ((flags & 0x0001) == 0) {
512 l = pi.captured_len - (offset + sizeof(*ni));
513 l /= sizeof(guint32);
516 if (!IS_DATA_IN_FRAME(p + sizeof(guint32) - 1 - pd))
519 i = pntohs(p + sizeof(guint16)); /*skip*/
521 if (n + l * 32 > (1 << 16))
523 if (n + (l + i) * 32 > (1 << 16))
525 if ((flags & 0x0001) == 0) {
526 proto_tree_add_text(field_tree, NullTVB, p - pd,
527 l * 4, "Bitmap (%d to %d): %s", n, n + l * 32 - 1,
531 proto_tree_add_text(field_tree, NullTVB, p - pd,
532 4 + l * 4, "Bitmap (%d to %d): %s", n, n + l * 32 - 1,
533 bitrange(p + 4, l, n));
536 n += l * 32 + i * 32;
538 off = pi.captured_len - offset;
540 case NI_QTYPE_DNSNAME:
541 proto_tree_add_text(tree, NullTVB, offset + sizeof(*ni),
542 sizeof(gint32), "TTL: %d", (gint32)pntohl(ni + 1));
543 tf = proto_tree_add_text(tree, NullTVB,
544 offset + sizeof(*ni) + sizeof(guint32), END_OF_FRAME,
546 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_nodedns);
548 i = offset + sizeof(*ni) + sizeof(guint32);
549 while (i < pi.captured_len) {
550 l = get_dns_name(pd, i, offset + sizeof(*ni), dname,
552 if (IS_DATA_IN_FRAME(i + l) && pd[i + l] == 0) {
554 proto_tree_add_text(field_tree, NullTVB, i, l,
555 "DNS label: %s (truncated)", dname);
557 proto_tree_add_text(field_tree, NullTVB, i, l,
558 "DNS label: %s", dname);
562 off = pi.captured_len - offset;
564 case NI_QTYPE_NODEADDR:
565 n = pi.captured_len - (offset + sizeof(*ni));
566 n /= sizeof(struct e_in6_addr) + sizeof(gint32);;
567 tf = proto_tree_add_text(tree, NullTVB,
568 offset + sizeof(*ni), END_OF_FRAME, "IPv6 node addresses");
569 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_node6);
570 p = (u_char *)(ni + 1);
571 for (i = 0; i < n; i++) {
572 proto_tree_add_text(field_tree, NullTVB,
573 p - pd, sizeof(struct e_in6_addr) + sizeof(gint32),
574 "%s (TTL %d)", ip6_to_str((struct e_in6_addr *)p),
575 (gint32)pntohl(p + sizeof(struct e_in6_addr)));
576 p += sizeof(struct e_in6_addr) + sizeof(gint32);
578 off = pi.captured_len - offset;
580 case NI_QTYPE_IPV4ADDR:
581 n = pi.captured_len - (offset + sizeof(*ni));
582 n /= sizeof(guint32);
583 tf = proto_tree_add_text(tree, NullTVB,
584 offset + sizeof(*ni), END_OF_FRAME, "IPv4 node addresses");
585 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_node4);
586 p = (u_char *)(ni + 1);
587 for (i = 0; i < n; i++) {
588 proto_tree_add_text(field_tree, NullTVB,
589 p - pd, sizeof(guint32), "%s", ip_to_str(p));
590 p += sizeof(guint32);
592 off = pi.captured_len - offset;
598 /* the rest of data */
599 old_dissect_data(pd, offset + off, fd, tree);
603 dissect_rrenum(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
605 proto_tree *field_tree, *opt_tree;
607 struct icmp6_router_renum *rr = (struct icmp6_router_renum *)&pd[offset];
608 struct rr_pco_match *match;
609 struct rr_pco_use *use;
612 proto_tree_add_text(tree, NullTVB,
613 offset + offsetof(struct icmp6_router_renum, rr_seqnum), 4,
614 "Sequence number: 0x%08x", pntohl(&rr->rr_seqnum));
615 proto_tree_add_text(tree, NullTVB,
616 offset + offsetof(struct icmp6_router_renum, rr_segnum), 1,
617 "Segment number: 0x%02x", rr->rr_segnum);
619 flagoff = offset + offsetof(struct icmp6_router_renum, rr_flags);
620 tf = proto_tree_add_text(tree, NullTVB, flagoff, 1,
621 "Flags: 0x%02x", pd[flagoff]);
622 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
623 proto_tree_add_text(field_tree, NullTVB, flagoff, 1, "%s",
624 decode_boolean_bitfield(pd[flagoff], 0x80, 8,
625 "Test command", "Not test command"));
626 proto_tree_add_text(field_tree, NullTVB, flagoff, 1, "%s",
627 decode_boolean_bitfield(pd[flagoff], 0x40, 8,
628 "Result requested", "Result not requested"));
629 proto_tree_add_text(field_tree, NullTVB, flagoff, 1, "%s",
630 decode_boolean_bitfield(pd[flagoff], 0x20, 8,
631 "All interfaces", "Not all interfaces"));
632 proto_tree_add_text(field_tree, NullTVB, flagoff, 1, "%s",
633 decode_boolean_bitfield(pd[flagoff], 0x10, 8,
634 "Site specific", "Not site specific"));
635 proto_tree_add_text(field_tree, NullTVB, flagoff, 1, "%s",
636 decode_boolean_bitfield(pd[flagoff], 0x08, 8,
637 "Processed previously", "Complete result"));
639 proto_tree_add_text(tree, NullTVB,
640 offset + offsetof(struct icmp6_router_renum, rr_maxdelay), 2,
641 "Max delay: 0x%04x", pntohs(&rr->rr_maxdelay));
642 old_dissect_data(pd, offset + sizeof(*rr), fd, tree); /*XXX*/
644 if (rr->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) {
645 off = offset + sizeof(*rr);
646 match = (struct rr_pco_match *)&pd[off];
647 tf = proto_tree_add_text(tree, NullTVB, off, sizeof(*match),
648 "Match-Prefix: %s/%u (%u-%u)", ip6_to_str(&match->rpm_prefix),
649 match->rpm_matchlen, match->rpm_minlen, match->rpm_maxlen);
650 opt_tree = proto_item_add_subtree(tf, ett_icmpv6opt);
651 proto_tree_add_text(opt_tree, NullTVB,
652 off + offsetof(struct rr_pco_match, rpm_code),
653 sizeof(match->rpm_code), "OpCode: %s (%u)",
654 val_to_str(match->rpm_code, names_rrenum_matchcode, "Unknown"),
656 proto_tree_add_text(opt_tree, NullTVB,
657 off + offsetof(struct rr_pco_match, rpm_len),
658 sizeof(match->rpm_len), "OpLength: %u (%u octets)",
659 match->rpm_len, match->rpm_len * 8);
660 proto_tree_add_text(opt_tree, NullTVB,
661 off + offsetof(struct rr_pco_match, rpm_ordinal),
662 sizeof(match->rpm_ordinal), "Ordinal: %u", match->rpm_ordinal);
663 proto_tree_add_text(opt_tree, NullTVB,
664 off + offsetof(struct rr_pco_match, rpm_matchlen),
665 sizeof(match->rpm_matchlen), "MatchLen: %u", match->rpm_matchlen);
666 proto_tree_add_text(opt_tree, NullTVB,
667 off + offsetof(struct rr_pco_match, rpm_minlen),
668 sizeof(match->rpm_minlen), "MinLen: %u", match->rpm_minlen);
669 proto_tree_add_text(opt_tree, NullTVB,
670 off + offsetof(struct rr_pco_match, rpm_maxlen),
671 sizeof(match->rpm_maxlen), "MaxLen: %u", match->rpm_maxlen);
672 proto_tree_add_text(opt_tree, NullTVB,
673 off + offsetof(struct rr_pco_match, rpm_prefix),
674 sizeof(match->rpm_prefix), "MatchPrefix: %s",
675 ip6_to_str(&match->rpm_prefix));
677 off += sizeof(*match);
678 use = (struct rr_pco_use *)&pd[off];
679 for (l = match->rpm_len * 8 - sizeof(*match);
680 l >= sizeof(*use); l -= sizeof(*use), off += sizeof(*use)) {
681 tf = proto_tree_add_text(tree, NullTVB, off, sizeof(*use),
682 "Use-Prefix: %s/%u (keep %u)", ip6_to_str(&use->rpu_prefix),
683 use->rpu_uselen, use->rpu_keeplen);
684 opt_tree = proto_item_add_subtree(tf, ett_icmpv6opt);
685 proto_tree_add_text(opt_tree, NullTVB,
686 off + offsetof(struct rr_pco_use, rpu_uselen),
687 sizeof(use->rpu_uselen), "UseLen: %u", use->rpu_uselen);
688 proto_tree_add_text(opt_tree, NullTVB,
689 off + offsetof(struct rr_pco_use, rpu_keeplen),
690 sizeof(use->rpu_keeplen), "KeepLen: %u", use->rpu_keeplen);
691 tf = proto_tree_add_text(opt_tree, NullTVB,
692 flagoff = off + offsetof(struct rr_pco_use, rpu_ramask),
693 sizeof(use->rpu_ramask), "FlagMask: 0x%x", use->rpu_ramask);
694 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
695 proto_tree_add_text(field_tree, NullTVB, flagoff, 1, "%s",
696 decode_boolean_bitfield(pd[flagoff],
697 ICMP6_RR_PCOUSE_RAFLAGS_ONLINK, 8,
698 "Onlink", "Not onlink"));
699 proto_tree_add_text(field_tree, NullTVB, flagoff, 1, "%s",
700 decode_boolean_bitfield(pd[flagoff],
701 ICMP6_RR_PCOUSE_RAFLAGS_AUTO, 8,
702 "Auto", "Not auto"));
703 tf = proto_tree_add_text(opt_tree, NullTVB,
704 flagoff = off + offsetof(struct rr_pco_use, rpu_raflags),
705 sizeof(use->rpu_raflags), "RAFlags: 0x%x", use->rpu_raflags);
706 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
707 proto_tree_add_text(field_tree, NullTVB, flagoff, 1, "%s",
708 decode_boolean_bitfield(pd[flagoff],
709 ICMP6_RR_PCOUSE_RAFLAGS_ONLINK, 8,
710 "Onlink", "Not onlink"));
711 proto_tree_add_text(field_tree, NullTVB, flagoff, 1, "%s",
712 decode_boolean_bitfield(pd[flagoff],
713 ICMP6_RR_PCOUSE_RAFLAGS_AUTO, 8, "Auto", "Not auto"));
714 if (pntohl(&use->rpu_vltime) == 0xffffffff)
715 proto_tree_add_text(opt_tree, NullTVB,
716 off + offsetof(struct rr_pco_use, rpu_vltime),
717 sizeof(use->rpu_vltime), "Valid Lifetime: infinity");
719 proto_tree_add_text(opt_tree, NullTVB,
720 off + offsetof(struct rr_pco_use, rpu_vltime),
721 sizeof(use->rpu_vltime), "Valid Lifetime: %u",
722 pntohl(&use->rpu_vltime));
723 if (pntohl(&use->rpu_pltime) == 0xffffffff)
724 proto_tree_add_text(opt_tree, NullTVB,
725 off + offsetof(struct rr_pco_use, rpu_pltime),
726 sizeof(use->rpu_pltime), "Preferred Lifetime: infinity");
728 proto_tree_add_text(opt_tree, NullTVB,
729 off + offsetof(struct rr_pco_use, rpu_pltime),
730 sizeof(use->rpu_pltime), "Preferred Lifetime: %u",
731 pntohl(&use->rpu_pltime));
732 tf = proto_tree_add_text(opt_tree, NullTVB,
733 flagoff = off + offsetof(struct rr_pco_use, rpu_flags),
734 sizeof(use->rpu_flags), "Flags: 0x%08x",
735 pntohl(&use->rpu_flags));
736 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
737 proto_tree_add_text(field_tree, NullTVB, flagoff, 4, "%s",
738 decode_boolean_bitfield(pd[flagoff],
739 ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, 32,
740 "Decrement valid lifetime", "No decrement valid lifetime"));
741 proto_tree_add_text(field_tree, NullTVB, flagoff, 4, "%s",
742 decode_boolean_bitfield(pd[flagoff],
743 ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, 32,
744 "Decrement preferred lifetime",
745 "No decrement preferred lifetime"));
746 proto_tree_add_text(opt_tree, NullTVB,
747 off + offsetof(struct rr_pco_use, rpu_prefix),
748 sizeof(use->rpu_prefix), "UsePrefix: %s",
749 ip6_to_str(&use->rpu_prefix));
756 dissect_icmpv6(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
758 proto_tree *icmp6_tree, *field_tree;
759 proto_item *ti, *tf = NULL;
760 struct icmp6_hdr *dp;
761 struct icmp6_nodeinfo *ni = NULL;
762 char *codename, *typename;
763 char *colcodename, *coltypename;
765 guint length, reported_length;
768 guint16 cksum, computed_cksum;
770 dp = (struct icmp6_hdr *)&pd[offset];
771 codename = typename = colcodename = coltypename = "Unknown";
773 switch (dp->icmp6_type) {
774 case ICMP6_DST_UNREACH:
775 typename = coltypename = "Unreachable";
776 switch (dp->icmp6_code) {
777 case ICMP6_DST_UNREACH_NOROUTE:
778 codename = colcodename = "Route unreachable";
780 case ICMP6_DST_UNREACH_ADMIN:
781 codename = colcodename = "Administratively prohibited";
783 case ICMP6_DST_UNREACH_NOTNEIGHBOR:
784 codename = colcodename = "Not a neighbor";
786 case ICMP6_DST_UNREACH_ADDR:
787 codename = colcodename = "Address unreachable";
789 case ICMP6_DST_UNREACH_NOPORT:
790 codename = colcodename = "Port unreachable";
794 case ICMP6_PACKET_TOO_BIG:
795 typename = coltypename = "Too big";
796 codename = colcodename = NULL;
798 case ICMP6_TIME_EXCEEDED:
799 typename = coltypename = "Time exceeded";
800 switch (dp->icmp6_code) {
801 case ICMP6_TIME_EXCEED_TRANSIT:
802 codename = colcodename = "In-transit";
804 case ICMP6_TIME_EXCEED_REASSEMBLY:
805 codename = colcodename = "Reassembly";
809 case ICMP6_PARAM_PROB:
810 typename = coltypename = "Parameter problem";
811 switch (dp->icmp6_code) {
812 case ICMP6_PARAMPROB_HEADER:
813 codename = colcodename = "Header";
815 case ICMP6_PARAMPROB_NEXTHEADER:
816 codename = colcodename = "Next header";
818 case ICMP6_PARAMPROB_OPTION:
819 codename = colcodename = "Option";
823 case ICMP6_ECHO_REQUEST:
824 typename = coltypename = "Echo request";
825 codename = colcodename = NULL;
827 case ICMP6_ECHO_REPLY:
828 typename = coltypename = "Echo reply";
829 codename = colcodename = NULL;
831 case ICMP6_MEMBERSHIP_QUERY:
832 typename = coltypename = "Multicast listener query";
833 codename = colcodename = NULL;
835 case ICMP6_MEMBERSHIP_REPORT:
836 typename = coltypename = "Multicast listener report";
837 codename = colcodename = NULL;
839 case ICMP6_MEMBERSHIP_REDUCTION:
840 typename = coltypename = "Multicast listener done";
841 codename = colcodename = NULL;
843 case ND_ROUTER_SOLICIT:
844 typename = coltypename = "Router solicitation";
845 codename = colcodename = NULL;
846 len = sizeof(struct nd_router_solicit);
848 case ND_ROUTER_ADVERT:
849 typename = coltypename = "Router advertisement";
850 codename = colcodename = NULL;
851 len = sizeof(struct nd_router_advert);
853 case ND_NEIGHBOR_SOLICIT:
854 typename = coltypename = "Neighbor solicitation";
855 codename = colcodename = NULL;
856 len = sizeof(struct nd_neighbor_solicit);
858 case ND_NEIGHBOR_ADVERT:
859 typename = coltypename = "Neighbor advertisement";
860 codename = colcodename = NULL;
861 len = sizeof(struct nd_neighbor_advert);
864 typename = coltypename = "Redirect";
865 codename = colcodename = NULL;
866 len = sizeof(struct nd_redirect);
868 case ICMP6_ROUTER_RENUMBERING:
869 typename = coltypename = "Router renumbering";
870 switch (dp->icmp6_code) {
871 case ICMP6_ROUTER_RENUMBERING_COMMAND:
872 codename = colcodename = "Command";
874 case ICMP6_ROUTER_RENUMBERING_RESULT:
875 codename = colcodename = "Result";
877 case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
878 codename = colcodename = "Sequence number reset";
881 len = sizeof(struct icmp6_router_renum);
885 ni = (struct icmp6_nodeinfo *)dp;
886 if (ni->ni_type == ICMP6_NI_QUERY) {
887 typename = coltypename = "Node information query";
888 switch (ni->ni_code) {
889 case ICMP6_NI_SUBJ_IPV6:
890 codename = "Query subject = IPv6 addresses";
892 case ICMP6_NI_SUBJ_FQDN:
893 if (IS_DATA_IN_FRAME(offset + sizeof(*ni)))
894 codename = "Query subject = DNS name";
896 codename = "Query subject = empty";
898 case ICMP6_NI_SUBJ_IPV4:
899 codename = "Query subject = IPv4 addresses";
903 typename = coltypename = "Node information reply";
904 switch (ni->ni_code) {
905 case ICMP6_NI_SUCCESS:
906 codename = "Successful";
908 case ICMP6_NI_REFUSED:
909 codename = "Refused";
911 case ICMP6_NI_UNKNOWN:
912 codename = "Unknown query type";
916 colcodename = val_to_str(pntohs(&ni->ni_qtype), names_nodeinfo_qtype,
918 len = sizeof(struct icmp6_nodeinfo);
922 if (check_col(fd, COL_PROTOCOL))
923 col_set_str(fd, COL_PROTOCOL, "ICMPv6");
924 if (check_col(fd, COL_INFO)) {
925 char typebuf[256], codebuf[256];
927 if (coltypename && strcmp(coltypename, "Unknown") == 0) {
928 snprintf(typebuf, sizeof(typebuf), "Unknown (0x%02x)",
930 coltypename = typebuf;
932 if (colcodename && strcmp(colcodename, "Unknown") == 0) {
933 snprintf(codebuf, sizeof(codebuf), "Unknown (0x%02x)",
935 colcodename = codebuf;
938 col_add_fstr(fd, COL_INFO, "%s (%s)", coltypename, colcodename);
940 col_add_fstr(fd, COL_INFO, "%s", coltypename);
945 /* !!! specify length */
946 ti = proto_tree_add_item(tree, proto_icmpv6, NullTVB, offset, len, FALSE);
947 icmp6_tree = proto_item_add_subtree(ti, ett_icmpv6);
949 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_type, NullTVB,
950 offset + offsetof(struct icmp6_hdr, icmp6_type), 1,
952 "Type: 0x%02x (%s)", dp->icmp6_type, typename);
954 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_code, NullTVB,
955 offset + offsetof(struct icmp6_hdr, icmp6_code), 1,
957 "Code: 0x%02x (%s)", dp->icmp6_code, codename);
959 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_code, NullTVB,
960 offset + offsetof(struct icmp6_hdr, icmp6_code), 1,
962 "Code: 0x%02x", dp->icmp6_code);
964 cksum = (guint16)htons(dp->icmp6_cksum);
965 length = pi.captured_len - offset;
966 reported_length = pi.len - offset;
967 if (!pi.fragmented && length >= reported_length) {
968 /* The packet isn't part of a fragmented datagram and isn't
969 truncated, so we can checksum it. */
971 /* Set up the fields of the pseudo-header. */
972 cksum_vec[0].ptr = pi.src.data;
973 cksum_vec[0].len = pi.src.len;
974 cksum_vec[1].ptr = pi.dst.data;
975 cksum_vec[1].len = pi.dst.len;
976 cksum_vec[2].ptr = (const guint8 *)&phdr;
977 phdr[0] = htonl(reported_length);
978 phdr[1] = htonl(IP_PROTO_ICMPV6);
979 cksum_vec[2].len = 8;
980 cksum_vec[3].ptr = &pd[offset];
981 cksum_vec[3].len = reported_length;
982 computed_cksum = in_cksum(cksum_vec, 4);
983 if (computed_cksum == 0) {
984 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_checksum,
986 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
988 "Checksum: 0x%04x (correct)", cksum);
990 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_checksum,
992 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
994 "Checksum: 0x%04x (incorrect, should be 0x%04x)",
995 cksum, in_cksum_shouldbe(cksum, computed_cksum));
998 proto_tree_add_uint(icmp6_tree, hf_icmpv6_checksum, NullTVB,
999 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1004 switch (dp->icmp6_type) {
1005 case ICMP6_DST_UNREACH:
1006 case ICMP6_TIME_EXCEEDED:
1007 /* tiny sanity check */
1008 if ((pd[offset + sizeof(*dp)] & 0xf0) == 0x60) {
1009 dissect_ipv6(pd, offset + sizeof(*dp), fd, icmp6_tree);
1011 old_dissect_data(pd, offset + sizeof(*dp), fd, icmp6_tree);
1014 case ICMP6_PACKET_TOO_BIG:
1015 proto_tree_add_text(icmp6_tree, NullTVB,
1016 offset + offsetof(struct icmp6_hdr, icmp6_mtu), 4,
1017 "MTU: %d", pntohl(&dp->icmp6_mtu));
1018 /* tiny sanity check */
1019 if ((pd[offset + sizeof(*dp)] & 0xf0) == 0x60) {
1020 dissect_ipv6(pd, offset + sizeof(*dp), fd, icmp6_tree);
1022 old_dissect_data(pd, offset + sizeof(*dp), fd, icmp6_tree);
1025 case ICMP6_PARAM_PROB:
1026 proto_tree_add_text(icmp6_tree, NullTVB,
1027 offset + offsetof(struct icmp6_hdr, icmp6_pptr), 4,
1028 "Problem pointer: 0x%04x", pntohl(&dp->icmp6_pptr));
1029 /* tiny sanity check */
1030 if ((pd[offset + sizeof(*dp)] & 0xf0) == 0x60) {
1031 dissect_ipv6(pd, offset + sizeof(*dp), fd, icmp6_tree);
1033 old_dissect_data(pd, offset + sizeof(*dp), fd, icmp6_tree);
1036 case ICMP6_ECHO_REQUEST:
1037 case ICMP6_ECHO_REPLY:
1038 proto_tree_add_text(icmp6_tree, NullTVB,
1039 offset + offsetof(struct icmp6_hdr, icmp6_id), 2,
1040 "ID: 0x%04x", (guint16)ntohs(dp->icmp6_id));
1041 proto_tree_add_text(icmp6_tree, NullTVB,
1042 offset + offsetof(struct icmp6_hdr, icmp6_seq), 2,
1043 "Sequence: 0x%04x", (guint16)ntohs(dp->icmp6_seq));
1044 old_dissect_data(pd, offset + sizeof(*dp), fd, icmp6_tree);
1046 case ICMP6_MEMBERSHIP_QUERY:
1047 case ICMP6_MEMBERSHIP_REPORT:
1048 case ICMP6_MEMBERSHIP_REDUCTION:
1049 proto_tree_add_text(icmp6_tree, NullTVB,
1050 offset + offsetof(struct icmp6_hdr, icmp6_maxdelay), 2,
1051 "Maximum response delay: %d",
1052 (guint16)ntohs(dp->icmp6_maxdelay));
1053 proto_tree_add_text(icmp6_tree, NullTVB, offset + sizeof(*dp), 16,
1054 "Multicast Address: %s",
1055 ip6_to_str((struct e_in6_addr *)(dp + 1)));
1057 case ND_ROUTER_SOLICIT:
1058 dissect_icmpv6opt(pd, offset + sizeof(*dp), fd, icmp6_tree);
1060 case ND_ROUTER_ADVERT:
1062 struct nd_router_advert *ra = (struct nd_router_advert *)dp;
1066 proto_tree_add_text(icmp6_tree, NullTVB,
1067 offset + offsetof(struct nd_router_advert, nd_ra_curhoplimit),
1068 1, "Cur hop limit: %d", ra->nd_ra_curhoplimit);
1070 flagoff = offset + offsetof(struct nd_router_advert, nd_ra_flags_reserved);
1071 ra_flags = pntohl(&pd[flagoff]);
1072 tf = proto_tree_add_text(icmp6_tree, NullTVB, flagoff, 4, "Flags: 0x%08x", ra_flags);
1073 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1074 proto_tree_add_text(field_tree, NullTVB, flagoff, 4, "%s",
1075 decode_boolean_bitfield(ra_flags,
1076 0x80000000, 32, "Managed", "Not managed"));
1077 proto_tree_add_text(field_tree, NullTVB, flagoff, 4, "%s",
1078 decode_boolean_bitfield(ra_flags,
1079 0x40000000, 32, "Other", "Not other"));
1080 /* BT INSERT BEGIN */
1081 proto_tree_add_text(field_tree, NullTVB, flagoff, 4, "%s",
1082 decode_boolean_bitfield(ra_flags,
1083 0x20000000, 32, "Home Agent", "Not Home Agent"));
1085 proto_tree_add_text(icmp6_tree, NullTVB,
1086 offset + offsetof(struct nd_router_advert, nd_ra_router_lifetime),
1087 2, "Router lifetime: %d",
1088 (guint16)ntohs(ra->nd_ra_router_lifetime));
1089 proto_tree_add_text(icmp6_tree, NullTVB,
1090 offset + offsetof(struct nd_router_advert, nd_ra_reachable), 4,
1091 "Reachable time: %d", pntohl(&ra->nd_ra_reachable));
1092 proto_tree_add_text(icmp6_tree, NullTVB,
1093 offset + offsetof(struct nd_router_advert, nd_ra_retransmit), 4,
1094 "Retrans time: %d", pntohl(&ra->nd_ra_retransmit));
1095 dissect_icmpv6opt(pd, offset + sizeof(struct nd_router_advert), fd, icmp6_tree);
1098 case ND_NEIGHBOR_SOLICIT:
1100 struct nd_neighbor_solicit *ns = (struct nd_neighbor_solicit *)dp;
1102 proto_tree_add_text(icmp6_tree, NullTVB,
1103 offset + offsetof(struct nd_neighbor_solicit, nd_ns_target), 16,
1106 get_hostname6(&ns->nd_ns_target),
1110 ip6_to_str(&ns->nd_ns_target));
1112 dissect_icmpv6opt(pd, offset + sizeof(*ns), fd, icmp6_tree);
1115 case ND_NEIGHBOR_ADVERT:
1117 int flagoff, targetoff;
1119 struct e_in6_addr *na_target_p;
1121 flagoff = offset + offsetof(struct nd_neighbor_advert, nd_na_flags_reserved);
1122 na_flags = pntohl(&pd[flagoff]);
1124 tf = proto_tree_add_text(icmp6_tree, NullTVB, flagoff, 4, "Flags: 0x%08x", na_flags);
1125 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1126 proto_tree_add_text(field_tree, NullTVB, flagoff, 4, "%s",
1127 decode_boolean_bitfield(na_flags,
1128 ND_NA_FLAG_ROUTER, 32, "Router", "Not router"));
1129 proto_tree_add_text(field_tree, NullTVB, flagoff, 4, "%s",
1130 decode_boolean_bitfield(na_flags,
1131 ND_NA_FLAG_SOLICITED, 32, "Solicited", "Not adverted"));
1132 proto_tree_add_text(field_tree, NullTVB, flagoff, 4, "%s",
1133 decode_boolean_bitfield(na_flags,
1134 ND_NA_FLAG_OVERRIDE, 32, "Override", "Not override"));
1136 targetoff = offset + offsetof(struct nd_neighbor_advert, nd_na_target);
1137 na_target_p = (struct e_in6_addr*) &pd[targetoff];
1138 proto_tree_add_text(icmp6_tree, NullTVB, targetoff, 16,
1141 get_hostname6(na_target_p),
1145 ip6_to_str(na_target_p));
1147 dissect_icmpv6opt(pd, offset + sizeof(struct nd_neighbor_advert), fd, icmp6_tree);
1152 struct nd_redirect *rd = (struct nd_redirect *)dp;
1154 proto_tree_add_text(icmp6_tree, NullTVB,
1155 offset + offsetof(struct nd_redirect, nd_rd_target), 16,
1158 get_hostname6(&rd->nd_rd_target),
1162 ip6_to_str(&rd->nd_rd_target));
1164 proto_tree_add_text(icmp6_tree, NullTVB,
1165 offset + offsetof(struct nd_redirect, nd_rd_dst), 16,
1167 "Destination: %s (%s)",
1168 get_hostname6(&rd->nd_rd_dst),
1172 ip6_to_str(&rd->nd_rd_dst));
1174 dissect_icmpv6opt(pd, offset + sizeof(*rd), fd, icmp6_tree);
1177 case ICMP6_ROUTER_RENUMBERING:
1178 dissect_rrenum(pd, offset, fd, icmp6_tree);
1180 case ICMP6_NI_QUERY:
1181 case ICMP6_NI_REPLY:
1182 ni = (struct icmp6_nodeinfo *)dp;
1183 proto_tree_add_text(icmp6_tree, NullTVB,
1184 offset + offsetof(struct icmp6_nodeinfo, ni_qtype),
1185 sizeof(ni->ni_qtype),
1186 "Query type: 0x%04x (%s)", pntohs(&ni->ni_qtype),
1187 val_to_str(pntohs(&ni->ni_qtype), names_nodeinfo_qtype,
1189 dissect_nodeinfo(pd, offset, fd, icmp6_tree);
1192 old_dissect_data(pd, offset + sizeof(*dp), fd, tree);
1199 proto_register_icmpv6(void)
1201 static hf_register_info hf[] = {
1203 { "Type", "icmpv6.type", FT_UINT8, BASE_HEX, NULL, 0x0,
1206 { "Code", "icmpv6.code", FT_UINT8, BASE_HEX, NULL, 0x0,
1208 { &hf_icmpv6_checksum,
1209 { "Checksum", "icmpv6.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
1212 static gint *ett[] = {
1217 &ett_nodeinfo_subject4,
1218 &ett_nodeinfo_subject6,
1219 &ett_nodeinfo_node4,
1220 &ett_nodeinfo_node6,
1221 &ett_nodeinfo_nodebitmap,
1222 &ett_nodeinfo_nodedns,
1225 proto_icmpv6 = proto_register_protocol("Internet Control Message Protocol v6",
1226 "ICMPv6", "icmpv6");
1227 proto_register_field_array(proto_icmpv6, hf, array_length(hf));
1228 proto_register_subtree_array(ett, array_length(ett));
1232 proto_reg_handoff_icmpv6(void)
1234 old_dissector_add("ip.proto", IP_PROTO_ICMPV6, dissect_icmpv6, proto_icmpv6);