2 * Routines for ICMPv6 packet disassembly
4 * $Id: packet-icmpv6.c,v 1.67 2002/08/28 21:00:17 jmayer 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 * HMIPv6 support added by Martti Kuparinen <martti.kuparinen@iki.fi>
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
44 #ifdef NEED_SNPRINTF_H
45 # include "snprintf.h"
48 #include <epan/packet.h>
49 #include "packet-ipv6.h"
50 #include "packet-dns.h"
52 #include <epan/resolv.h>
56 #define offsetof(type, member) ((size_t)(&((type *)0)->member))
60 * See, under http://www.ietf.org/internet-drafts/
62 * draft-ietf-mobileip-ipv6-15.txt
66 * draft-ietf-ipngwg-icmp-name-lookups-08.txt
70 * draft-ietf-mobileip-hmipv6-05.txt
73 static int proto_icmpv6 = -1;
74 static int hf_icmpv6_type = -1;
75 static int hf_icmpv6_code = -1;
76 static int hf_icmpv6_checksum = -1;
77 static int hf_icmpv6_checksum_bad = -1;
79 static gint ett_icmpv6 = -1;
80 static gint ett_icmpv6opt = -1;
81 static gint ett_icmpv6flag = -1;
82 static gint ett_nodeinfo_flag = -1;
83 static gint ett_nodeinfo_subject4 = -1;
84 static gint ett_nodeinfo_subject6 = -1;
85 static gint ett_nodeinfo_node4 = -1;
86 static gint ett_nodeinfo_node6 = -1;
87 static gint ett_nodeinfo_nodebitmap = -1;
88 static gint ett_nodeinfo_nodedns = -1;
90 static dissector_handle_t ipv6_handle;
91 static dissector_handle_t data_handle;
93 static const value_string names_nodeinfo_qtype[] = {
94 { NI_QTYPE_NOOP, "NOOP" },
95 { NI_QTYPE_SUPTYPES, "Supported query types" },
96 { NI_QTYPE_DNSNAME, "DNS name" },
97 { NI_QTYPE_NODEADDR, "Node addresses" },
98 { NI_QTYPE_IPV4ADDR, "IPv4 node addresses" },
102 static const value_string names_rrenum_matchcode[] = {
103 { RPM_PCO_ADD, "Add" },
104 { RPM_PCO_CHANGE, "Change" },
105 { RPM_PCO_SETGLOBAL, "Set Global" },
109 static const value_string names_router_pref[] = {
110 { ND_RA_FLAG_RTPREF_HIGH, "High" },
111 { ND_RA_FLAG_RTPREF_MEDIUM, "Medium" },
112 { ND_RA_FLAG_RTPREF_LOW, "Low" },
113 { ND_RA_FLAG_RTPREF_RSV, "Reserved" },
117 dissect_contained_icmpv6(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
120 volatile address save_dl_src;
121 volatile address save_dl_dst;
122 volatile address save_net_src;
123 volatile address save_net_dst;
124 volatile address save_src;
125 volatile address save_dst;
126 gboolean save_in_error_pkt;
128 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
130 /* tiny sanity check */
131 if ((tvb_get_guint8(tvb, offset) & 0xf0) == 0x60) {
132 /* The contained packet is an IPv6 datagram; dissect it.
134 Set the columns non-writable, so that the packet list
135 shows this as an ICMPv6 packet, not as the type of packet
136 for which the ICMPv6 packet was generated. */
137 col_set_writable(pinfo->cinfo, FALSE);
139 /* Also, save the current values of the addresses, and restore
140 them when we're finished dissecting the contained packet, so
141 that the address columns in the summary don't reflect the
142 contained packet, but reflect this packet instead. */
143 save_dl_src = pinfo->dl_src;
144 save_dl_dst = pinfo->dl_dst;
145 save_net_src = pinfo->net_src;
146 save_net_dst = pinfo->net_dst;
147 save_src = pinfo->src;
148 save_dst = pinfo->dst;
150 /* Save the current value of the "we're inside an error packet"
151 flag, and set that flag; subdissectors may treat packets
152 that are the payload of error packets differently from
154 save_in_error_pkt = pinfo->in_error_pkt;
155 pinfo->in_error_pkt = TRUE;
157 /* Dissect the contained packet.
158 Catch ReportedBoundsError, and do nothing if we see it,
159 because it's not an error if the contained packet is short;
160 there's no guarantee that all of it was included.
162 XXX - should catch BoundsError, and re-throw it after cleaning
165 call_dissector(ipv6_handle, next_tvb, pinfo, tree);
167 CATCH(ReportedBoundsError) {
172 /* Restore the "we're inside an error packet" flag. */
173 pinfo->in_error_pkt = save_in_error_pkt;
175 /* Restore the addresses. */
176 pinfo->dl_src = save_dl_src;
177 pinfo->dl_dst = save_dl_dst;
178 pinfo->net_src = save_net_src;
179 pinfo->net_dst = save_net_dst;
180 pinfo->src = save_src;
181 pinfo->dst = save_dst;
183 call_dissector(data_handle,next_tvb, pinfo, tree);
187 dissect_icmpv6opt(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
189 proto_tree *icmp6opt_tree, *field_tree;
191 struct nd_opt_hdr nd_opt_hdr, *opt;
199 if ((int)tvb_reported_length(tvb) <= offset)
200 return; /* No more options left */
203 tvb_memcpy(tvb, (guint8 *)opt, offset, sizeof *opt);
204 len = opt->nd_opt_len << 3;
206 /* !!! specify length */
207 ti = proto_tree_add_text(tree, tvb, offset, len, "ICMPv6 options");
208 icmp6opt_tree = proto_item_add_subtree(ti, ett_icmpv6opt);
211 proto_tree_add_text(icmp6opt_tree, tvb,
212 offset + offsetof(struct nd_opt_hdr, nd_opt_len), 1,
213 "Invalid option length: %u",
215 return; /* we must not try to decode this */
218 switch (opt->nd_opt_type) {
219 case ND_OPT_SOURCE_LINKADDR:
220 typename = "Source link-layer address";
222 case ND_OPT_TARGET_LINKADDR:
223 typename = "Target link-layer address";
225 case ND_OPT_PREFIX_INFORMATION:
226 typename = "Prefix information";
228 case ND_OPT_REDIRECTED_HEADER:
229 typename = "Redirected header";
234 case ND_OPT_ADVINTERVAL:
235 typename = "Advertisement Interval";
237 case ND_OPT_HOMEAGENT_INFO:
238 typename = "Home Agent Information";
241 typename = "HMIPv6 MAP option";
244 typename = "Unknown";
248 proto_tree_add_text(icmp6opt_tree, tvb,
249 offset + offsetof(struct nd_opt_hdr, nd_opt_type), 1,
250 "Type: %u (%s)", opt->nd_opt_type, typename);
251 proto_tree_add_text(icmp6opt_tree, tvb,
252 offset + offsetof(struct nd_opt_hdr, nd_opt_len), 1,
253 "Length: %u bytes (%u)", opt->nd_opt_len << 3, opt->nd_opt_len);
256 switch (opt->nd_opt_type) {
257 case ND_OPT_SOURCE_LINKADDR:
258 case ND_OPT_TARGET_LINKADDR:
262 len = (opt->nd_opt_len << 3) - sizeof(*opt);
263 t = (char *)malloc(len * 3);
264 memset(t, 0, len * 3);
265 p = offset + sizeof(*opt);
266 for (i = 0; i < len; i++) {
269 sprintf(&t[i * 3], "%02x", tvb_get_guint8(tvb, p + i) & 0xff);
271 proto_tree_add_text(icmp6opt_tree, tvb,
272 offset + sizeof(*opt), len, "Link-layer address: %s", t);
276 case ND_OPT_PREFIX_INFORMATION:
278 struct nd_opt_prefix_info nd_opt_prefix_info, *pi;
281 pi = &nd_opt_prefix_info;
282 tvb_memcpy(tvb, (guint8 *)pi, offset, sizeof *pi);
283 proto_tree_add_text(icmp6opt_tree, tvb,
284 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_prefix_len),
285 1, "Prefix length: %u", pi->nd_opt_pi_prefix_len);
287 flagoff = offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_flags_reserved);
288 tf = proto_tree_add_text(icmp6opt_tree, tvb, flagoff, 1, "Flags: 0x%02x",
289 tvb_get_guint8(tvb, offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_flags_reserved)));
290 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
291 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
292 decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
293 ND_OPT_PI_FLAG_ONLINK, 8, "Onlink", "Not onlink"));
294 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
295 decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
296 ND_OPT_PI_FLAG_AUTO, 8, "Auto", "Not auto"));
297 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
298 decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
299 ND_OPT_PI_FLAG_ROUTER, 8,
300 "Router Address", "Not router address"));
301 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
302 decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
303 ND_OPT_PI_FLAG_SITEPREF, 8,
304 "Site prefix", "Not site prefix"));
305 proto_tree_add_text(icmp6opt_tree, tvb,
306 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_valid_time),
307 4, "Valid lifetime: 0x%08x",
308 pntohl(&pi->nd_opt_pi_valid_time));
309 proto_tree_add_text(icmp6opt_tree, tvb,
310 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_preferred_time),
311 4, "Preferred lifetime: 0x%08x",
312 pntohl(&pi->nd_opt_pi_preferred_time));
313 proto_tree_add_text(icmp6opt_tree, tvb,
314 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_prefix),
315 16, "Prefix: %s", ip6_to_str(&pi->nd_opt_pi_prefix));
318 case ND_OPT_REDIRECTED_HEADER:
319 proto_tree_add_text(icmp6opt_tree, tvb,
320 offset + 8, (opt->nd_opt_len << 3) - 8, "Redirected packet");
321 dissect_contained_icmpv6(tvb, offset + 8, pinfo, icmp6opt_tree);
324 proto_tree_add_text(icmp6opt_tree, tvb,
325 offset + offsetof(struct nd_opt_mtu, nd_opt_mtu_mtu), 4,
326 "MTU: %u", tvb_get_ntohl(tvb, offset + offsetof(struct nd_opt_mtu, nd_opt_mtu_mtu)));
328 case ND_OPT_ADVINTERVAL:
329 proto_tree_add_text(icmp6opt_tree, tvb,
330 offset + offsetof(struct nd_opt_adv_int, nd_opt_adv_int_advint), 4,
331 "Advertisement Interval: %u",
332 tvb_get_ntohl(tvb, offset + offsetof(struct nd_opt_adv_int, nd_opt_adv_int_advint)));
334 case ND_OPT_HOMEAGENT_INFO:
336 struct nd_opt_ha_info pibuf, *pi;
339 tvb_memcpy(tvb, (guint8 *)pi, offset, sizeof *pi);
340 proto_tree_add_text(icmp6opt_tree, tvb,
341 offset + offsetof(struct nd_opt_ha_info, nd_opt_ha_info_ha_pref),
342 2, "Home Agent Preference: %d",
343 (gint16)pntohs(&pi->nd_opt_ha_info_ha_pref));
344 proto_tree_add_text(icmp6opt_tree, tvb,
345 offset + offsetof(struct nd_opt_ha_info, nd_opt_ha_info_ha_life),
346 2, "Home Agent Lifetime: %u",
347 pntohs(&pi->nd_opt_ha_info_ha_life));
352 struct nd_opt_map_info mapbuf, *map;
356 tvb_memcpy(tvb, (guint8 *)map, offset, sizeof *map);
357 proto_tree_add_text(icmp6opt_tree, tvb,
358 offset + offsetof(struct nd_opt_map_info, nd_opt_map_dist_and_pref),
359 1, "Distance: %u", (map->nd_opt_map_dist_and_pref >> 4));
360 proto_tree_add_text(icmp6opt_tree, tvb,
361 offset + offsetof(struct nd_opt_map_info, nd_opt_map_dist_and_pref),
362 1, "Preference: %u", (map->nd_opt_map_dist_and_pref & 0x0F));
363 flagoff = offset + offsetof(struct nd_opt_map_info,
365 tf = proto_tree_add_text(icmp6opt_tree, tvb, flagoff, 1,
367 tvb_get_guint8(tvb, offset + offsetof(struct nd_opt_map_info,
369 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
370 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
371 decode_boolean_bitfield(map->nd_opt_map_flags,
372 ND_OPT_MAP_FLAG_R, 8, "R", "No R"));
373 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
374 decode_boolean_bitfield(map->nd_opt_map_flags,
375 ND_OPT_MAP_FLAG_M, 8, "M", "No M"));
376 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
377 decode_boolean_bitfield(map->nd_opt_map_flags,
378 ND_OPT_MAP_FLAG_I, 8, "I", "No I"));
379 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
380 decode_boolean_bitfield(map->nd_opt_map_flags,
381 ND_OPT_MAP_FLAG_T, 8, "T", "No T"));
382 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
383 decode_boolean_bitfield(map->nd_opt_map_flags,
384 ND_OPT_MAP_FLAG_P, 8, "P", "No P"));
385 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
386 decode_boolean_bitfield(map->nd_opt_map_flags,
387 ND_OPT_MAP_FLAG_V, 8, "V", "No V"));
388 proto_tree_add_text(icmp6opt_tree, tvb,
389 offset + offsetof(struct nd_opt_map_info, nd_opt_map_lifetime),
390 4, "Lifetime: %u", pntohl(&map->nd_opt_map_lifetime));
392 proto_tree_add_text(icmp6opt_tree, tvb,
393 offset + offsetof(struct nd_opt_map_info, nd_opt_map_address), 16,
395 "Address of MAP: %s (%s)",
396 get_hostname6(&map->nd_opt_map_address),
398 "Address of MAP: %s",
400 ip6_to_str(&map->nd_opt_map_address));
403 case ND_OPT_ROUTE_INFO:
405 struct nd_opt_route_info ribuf, *ri;
406 struct e_in6_addr in6;
411 tvb_memcpy(tvb, (guint8 *)ri, offset, sizeof *ri);
412 memset(&in6, 0, sizeof(in6));
413 switch (ri->nd_opt_rti_len) {
418 tvb_memcpy(tvb, (guint8 *)&in6, offset + sizeof(*ri), l = 8);
421 tvb_memcpy(tvb, (guint8 *)&in6, offset + sizeof(*ri), l = 16);
428 proto_tree_add_text(icmp6opt_tree, tvb,
429 offset + offsetof(struct nd_opt_route_info, nd_opt_rti_prefixlen),
430 1, "Prefix length: %u", ri->nd_opt_rti_prefixlen);
431 tf = proto_tree_add_text(icmp6opt_tree, tvb,
432 offset + offsetof(struct nd_opt_route_info, nd_opt_rti_flags),
433 1, "Flags: 0x%02x", ri->nd_opt_rti_flags);
434 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
435 proto_tree_add_text(field_tree, tvb,
436 offset + offsetof(struct nd_opt_route_info, nd_opt_rti_flags),
438 decode_enumerated_bitfield(ri->nd_opt_rti_flags,
439 ND_RA_FLAG_RTPREF_MASK, 8, names_router_pref,
440 "Router preference: %s"));
441 lifetime = pntohl(&ri->nd_opt_rti_lifetime);
442 if (lifetime == 0xffffffff)
443 proto_tree_add_text(icmp6opt_tree, tvb,
444 offset + offsetof(struct nd_opt_route_info, nd_opt_rti_lifetime),
445 sizeof(ri->nd_opt_rti_lifetime), "Lifetime: infinity");
447 proto_tree_add_text(icmp6opt_tree, tvb,
448 offset + offsetof(struct nd_opt_route_info, nd_opt_rti_lifetime),
449 sizeof(ri->nd_opt_rti_lifetime), "Lifetime: %u", lifetime);
450 proto_tree_add_text(icmp6opt_tree, tvb,
451 offset + sizeof(*ri), l, "Prefix: %s", ip6_to_str(&in6));
453 proto_tree_add_text(icmp6opt_tree, tvb,
454 offset + offsetof(struct nd_opt_hdr, nd_opt_len), 1,
455 "Invalid option length: %u", opt->nd_opt_len);
461 offset += (opt->nd_opt_len << 3);
466 * draft-ietf-ipngwg-icmp-name-lookups-07.txt
467 * Note that the packet format was changed several times in the past.
471 bitrange0(v, s, buf, buflen)
491 ep = buf + buflen - 1;
492 memset(buf, 0, buflen);
495 /* shift till we have 0x01 */
496 if ((v & 0x01) == 0) {
499 v >>= 4; off += 4; continue;
501 v >>= 3; off += 3; continue;
502 case 0x04: case 0x0c:
503 v >>= 2; off += 2; continue;
505 v >>= 1; off += 1; continue;
509 /* we have 0x01 with us */
510 for (i = 0; i < 32 - off; i++) {
511 if ((v & (0x01 << i)) == 0)
515 l = snprintf(p, ep - p, ",%d", s + off);
517 l = snprintf(p, ep - p, ",%d-%d", s + off,
520 if (l == -1 || l > ep - p) {
531 bitrange(tvbuff_t *tvb, int offset, int l, int s)
533 static char buf[1024];
537 memset(buf, 0, sizeof(buf));
539 eq = buf + sizeof(buf) - 1;
540 for (i = 0; i < l; i++) {
541 if (bitrange0(tvb_get_ntohl(tvb, offset + i * 4), s + i * 4, q, eq - q) == NULL) {
542 if (q != buf && q + 5 < buf + sizeof(buf))
543 strncpy(q, ",...", 5);
552 dissect_nodeinfo(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
554 proto_tree *field_tree;
556 struct icmp6_nodeinfo icmp6_nodeinfo, *ni;
561 char dname[MAXDNAME];
564 ni = &icmp6_nodeinfo;
565 tvb_memcpy(tvb, (guint8 *)ni, offset, sizeof *ni);
567 flags = pntohs(&ni->ni_flags);
568 tf = proto_tree_add_text(tree, tvb,
569 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
570 sizeof(ni->ni_flags), "Flags: 0x%04x", flags);
571 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_flag);
572 switch (pntohs(&ni->ni_qtype)) {
573 case NI_QTYPE_SUPTYPES:
574 if (ni->ni_type == ICMP6_NI_QUERY) {
575 proto_tree_add_text(field_tree, tvb,
576 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
577 sizeof(ni->ni_flags), "%s",
578 decode_boolean_bitfield(flags, NI_SUPTYPE_FLAG_COMPRESS, sizeof(flags) * 8,
579 "Compressed reply supported",
580 "No compressed reply support"));
582 proto_tree_add_text(field_tree, tvb,
583 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
584 sizeof(ni->ni_flags), "%s",
585 decode_boolean_bitfield(flags, NI_SUPTYPE_FLAG_COMPRESS, sizeof(flags) * 8,
586 "Compressed", "Not compressed"));
589 case NI_QTYPE_DNSNAME:
590 if (ni->ni_type == ICMP6_NI_REPLY) {
591 proto_tree_add_text(field_tree, tvb,
592 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
593 sizeof(ni->ni_flags), "%s",
594 decode_boolean_bitfield(flags, NI_FQDN_FLAG_VALIDTTL, sizeof(flags) * 8,
595 "Valid TTL field", "Meaningless TTL field"));
598 case NI_QTYPE_NODEADDR:
599 proto_tree_add_text(field_tree, tvb,
600 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
601 sizeof(ni->ni_flags), "%s",
602 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_GLOBAL, sizeof(flags) * 8,
604 "Not global address"));
605 proto_tree_add_text(field_tree, tvb,
606 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
607 sizeof(ni->ni_flags), "%s",
608 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_SITELOCAL, sizeof(flags) * 8,
609 "Site-local address",
610 "Not site-local address"));
611 proto_tree_add_text(field_tree, tvb,
612 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
613 sizeof(ni->ni_flags), "%s",
614 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_LINKLOCAL, sizeof(flags) * 8,
615 "Link-local address",
616 "Not link-local address"));
617 proto_tree_add_text(field_tree, tvb,
618 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
619 sizeof(ni->ni_flags), "%s",
620 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_COMPAT, sizeof(flags) * 8,
621 "IPv4 compatible/mapped address",
622 "Not IPv4 compatible/mapped address"));
624 case NI_QTYPE_IPV4ADDR:
625 proto_tree_add_text(field_tree, tvb,
626 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
627 sizeof(ni->ni_flags), "%s",
628 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_ALL, sizeof(flags) * 8,
629 "All unicast address",
630 "Unicast addresses on the queried interface"));
631 proto_tree_add_text(field_tree, tvb,
632 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
633 sizeof(ni->ni_flags), "%s",
634 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_TRUNCATE, sizeof(flags) * 8,
635 "Truncated", "Not truncated"));
640 proto_tree_add_text(tree, tvb,
641 offset + offsetof(struct icmp6_nodeinfo, icmp6_ni_nonce[0]),
642 sizeof(ni->icmp6_ni_nonce), "Nonce: 0x%08x%08x",
643 pntohl(&ni->icmp6_ni_nonce[0]), pntohl(&ni->icmp6_ni_nonce[4]));
645 /* offset for "the rest of data" */
649 if (!tvb_bytes_exist(tvb, offset, sizeof(*ni)))
651 if (ni->ni_type == ICMP6_NI_QUERY) {
652 switch (ni->ni_code) {
653 case ICMP6_NI_SUBJ_IPV6:
654 n = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
655 n /= sizeof(struct e_in6_addr);
656 tf = proto_tree_add_text(tree, tvb,
657 offset + sizeof(*ni), -1, "IPv6 subject addresses");
658 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_subject6);
659 p = offset + sizeof *ni;
660 for (i = 0; i < n; i++) {
661 struct e_in6_addr e_in6_addr;
662 tvb_memcpy(tvb, (guint8 *)&e_in6_addr, p, sizeof e_in6_addr);
663 proto_tree_add_text(field_tree, tvb,
664 p, sizeof(struct e_in6_addr),
665 "%s", ip6_to_str(&e_in6_addr));
666 p += sizeof(struct e_in6_addr);
668 off = tvb_length_remaining(tvb, offset);
670 case ICMP6_NI_SUBJ_FQDN:
671 l = get_dns_name(tvb, offset + sizeof(*ni),
672 offset + sizeof(*ni), dname, sizeof(dname));
673 if (tvb_bytes_exist(tvb, offset + sizeof(*ni) + l, 1) &&
674 tvb_get_guint8(tvb, offset + sizeof(*ni) + l) == 0) {
676 proto_tree_add_text(tree, tvb, offset + sizeof(*ni), l,
677 "DNS label: %s (truncated)", dname);
679 proto_tree_add_text(tree, tvb, offset + sizeof(*ni), l,
680 "DNS label: %s", dname);
682 off = tvb_length_remaining(tvb, offset + sizeof(*ni) + l);
684 case ICMP6_NI_SUBJ_IPV4:
685 n = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
686 n /= sizeof(guint32);
687 tf = proto_tree_add_text(tree, tvb,
688 offset + sizeof(*ni), -1, "IPv4 subject addresses");
689 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_subject4);
690 p = offset + sizeof *ni;
691 for (i = 0; i < n; i++) {
692 tvb_memcpy(tvb, ipaddr, p, 4);
693 proto_tree_add_text(field_tree, tvb,
694 p, sizeof(guint32), "%s", ip_to_str(ipaddr));
695 p += sizeof(guint32);
697 off = tvb_length_remaining(tvb, offset);
701 switch (pntohs(&ni->ni_qtype)) {
704 case NI_QTYPE_SUPTYPES:
705 p = offset + sizeof *ni;
706 tf = proto_tree_add_text(tree, tvb,
707 offset + sizeof(*ni), -1,
708 "Supported type bitmap%s",
709 (flags & 0x0001) ? ", compressed" : "");
710 field_tree = proto_item_add_subtree(tf,
711 ett_nodeinfo_nodebitmap);
713 while (tvb_bytes_exist(tvb, p, sizeof(guint32))) { /* XXXX Check what? */
714 if ((flags & 0x0001) == 0) {
715 l = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
716 l /= sizeof(guint32);
719 l = tvb_get_ntohs(tvb, p);
720 i = tvb_get_ntohs(tvb, p + sizeof(guint16)); /*skip*/
722 if (n + l * 32 > (1 << 16))
724 if (n + (l + i) * 32 > (1 << 16))
726 if ((flags & 0x0001) == 0) {
727 proto_tree_add_text(field_tree, tvb, p,
728 l * 4, "Bitmap (%d to %d): %s", n, n + l * 32 - 1,
729 bitrange(tvb, p, l, n));
732 proto_tree_add_text(field_tree, tvb, p,
733 4 + l * 4, "Bitmap (%d to %d): %s", n, n + l * 32 - 1,
734 bitrange(tvb, p + 4, l, n));
737 n += l * 32 + i * 32;
739 off = tvb_length_remaining(tvb, offset);
741 case NI_QTYPE_DNSNAME:
742 proto_tree_add_text(tree, tvb, offset + sizeof(*ni),
743 sizeof(gint32), "TTL: %d", (gint32)tvb_get_ntohl(tvb, offset + sizeof *ni));
744 tf = proto_tree_add_text(tree, tvb,
745 offset + sizeof(*ni) + sizeof(guint32), -1,
747 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_nodedns);
748 j = offset + sizeof (*ni) + sizeof(guint32);
749 while (j < tvb_reported_length(tvb)) {
750 l = get_dns_name(tvb, j,
751 offset + sizeof (*ni) + sizeof(guint32),
752 dname,sizeof(dname));
753 if (tvb_bytes_exist(tvb, j + l, 1) &&
754 tvb_get_guint8(tvb, j + l) == 0) {
756 proto_tree_add_text(field_tree, tvb, j, l,
757 "DNS label: %s (truncated)", dname);
759 proto_tree_add_text(field_tree, tvb, j, l,
760 "DNS label: %s", dname);
764 off = tvb_length_remaining(tvb, offset);
766 case NI_QTYPE_NODEADDR:
767 n = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
768 n /= sizeof(gint32) + sizeof(struct e_in6_addr);
769 tf = proto_tree_add_text(tree, tvb,
770 offset + sizeof(*ni), -1, "IPv6 node addresses");
771 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_node6);
772 p = offset + sizeof (*ni);
773 for (i = 0; i < n; i++) {
774 struct e_in6_addr e_in6_addr;
776 ttl = (gint32)tvb_get_ntohl(tvb, p);
777 tvb_memcpy(tvb, (guint8 *)&e_in6_addr, p + sizeof ttl, sizeof e_in6_addr);
778 proto_tree_add_text(field_tree, tvb,
779 p, sizeof(struct e_in6_addr) + sizeof(gint32),
780 "%s (TTL %d)", ip6_to_str(&e_in6_addr), ttl);
781 p += sizeof(struct e_in6_addr) + sizeof(gint32);
783 off = tvb_length_remaining(tvb, offset);
785 case NI_QTYPE_IPV4ADDR:
786 n = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
787 n /= sizeof(gint32) + sizeof(guint32);
788 tf = proto_tree_add_text(tree, tvb,
789 offset + sizeof(*ni), -1, "IPv4 node addresses");
790 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_node4);
791 p = offset + sizeof *ni;
792 for (i = 0; i < n; i++) {
793 tvb_memcpy(tvb, ipaddr, sizeof(gint32) + p, 4);
794 proto_tree_add_text(field_tree, tvb,
795 p, sizeof(guint32), "%s (TTL %d)", ip_to_str(ipaddr), tvb_get_ntohl(tvb, p));
796 p += sizeof(gint32) + sizeof(guint32);
798 off = tvb_length_remaining(tvb, offset);
804 /* the rest of data */
805 call_dissector(data_handle,tvb_new_subset(tvb, offset + off, -1, -1), pinfo, tree);
809 dissect_rrenum(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
811 proto_tree *field_tree, *opt_tree;
813 struct icmp6_router_renum icmp6_router_renum, *rr;
814 struct rr_pco_match rr_pco_match, *match;
815 struct rr_pco_use rr_pco_use, *use;
820 rr = &icmp6_router_renum;
821 tvb_memcpy(tvb, (guint8 *)rr, offset, sizeof *rr);
822 proto_tree_add_text(tree, tvb,
823 offset + offsetof(struct icmp6_router_renum, rr_seqnum), 4,
824 "Sequence number: 0x%08x", pntohl(&rr->rr_seqnum));
825 proto_tree_add_text(tree, tvb,
826 offset + offsetof(struct icmp6_router_renum, rr_segnum), 1,
827 "Segment number: 0x%02x", rr->rr_segnum);
829 flagoff = offset + offsetof(struct icmp6_router_renum, rr_flags);
830 flags = tvb_get_guint8(tvb, flagoff);
831 tf = proto_tree_add_text(tree, tvb, flagoff, 1,
832 "Flags: 0x%02x", flags);
833 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
834 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
835 decode_boolean_bitfield(flags, 0x80, 8,
836 "Test command", "Not test command"));
837 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
838 decode_boolean_bitfield(flags, 0x40, 8,
839 "Result requested", "Result not requested"));
840 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
841 decode_boolean_bitfield(flags, 0x20, 8,
842 "All interfaces", "Not all interfaces"));
843 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
844 decode_boolean_bitfield(flags, 0x10, 8,
845 "Site specific", "Not site specific"));
846 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
847 decode_boolean_bitfield(flags, 0x08, 8,
848 "Processed previously", "Complete result"));
850 proto_tree_add_text(tree, tvb,
851 offset + offsetof(struct icmp6_router_renum, rr_maxdelay), 2,
852 "Max delay: 0x%04x", pntohs(&rr->rr_maxdelay));
853 call_dissector(data_handle,tvb_new_subset(tvb, offset + sizeof(*rr), -1, -1), pinfo, tree); /*XXX*/
855 if (rr->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) {
856 off = offset + sizeof(*rr);
857 match = &rr_pco_match;
858 tvb_memcpy(tvb, (guint8 *)match, off, sizeof *match);
859 tf = proto_tree_add_text(tree, tvb, off, sizeof(*match),
860 "Match-Prefix: %s/%u (%u-%u)", ip6_to_str(&match->rpm_prefix),
861 match->rpm_matchlen, match->rpm_minlen, match->rpm_maxlen);
862 opt_tree = proto_item_add_subtree(tf, ett_icmpv6opt);
863 proto_tree_add_text(opt_tree, tvb,
864 off + offsetof(struct rr_pco_match, rpm_code),
865 sizeof(match->rpm_code), "OpCode: %s (%u)",
866 val_to_str(match->rpm_code, names_rrenum_matchcode, "Unknown"),
868 proto_tree_add_text(opt_tree, tvb,
869 off + offsetof(struct rr_pco_match, rpm_len),
870 sizeof(match->rpm_len), "OpLength: %u (%u octets)",
871 match->rpm_len, match->rpm_len * 8);
872 proto_tree_add_text(opt_tree, tvb,
873 off + offsetof(struct rr_pco_match, rpm_ordinal),
874 sizeof(match->rpm_ordinal), "Ordinal: %u", match->rpm_ordinal);
875 proto_tree_add_text(opt_tree, tvb,
876 off + offsetof(struct rr_pco_match, rpm_matchlen),
877 sizeof(match->rpm_matchlen), "MatchLen: %u", match->rpm_matchlen);
878 proto_tree_add_text(opt_tree, tvb,
879 off + offsetof(struct rr_pco_match, rpm_minlen),
880 sizeof(match->rpm_minlen), "MinLen: %u", match->rpm_minlen);
881 proto_tree_add_text(opt_tree, tvb,
882 off + offsetof(struct rr_pco_match, rpm_maxlen),
883 sizeof(match->rpm_maxlen), "MaxLen: %u", match->rpm_maxlen);
884 proto_tree_add_text(opt_tree, tvb,
885 off + offsetof(struct rr_pco_match, rpm_prefix),
886 sizeof(match->rpm_prefix), "MatchPrefix: %s",
887 ip6_to_str(&match->rpm_prefix));
889 off += sizeof(*match);
891 for (l = match->rpm_len * 8 - sizeof(*match);
892 l >= sizeof(*use); l -= sizeof(*use), off += sizeof(*use)) {
893 tvb_memcpy(tvb, (guint8 *)use, off, sizeof *use);
894 tf = proto_tree_add_text(tree, tvb, off, sizeof(*use),
895 "Use-Prefix: %s/%u (keep %u)", ip6_to_str(&use->rpu_prefix),
896 use->rpu_uselen, use->rpu_keeplen);
897 opt_tree = proto_item_add_subtree(tf, ett_icmpv6opt);
898 proto_tree_add_text(opt_tree, tvb,
899 off + offsetof(struct rr_pco_use, rpu_uselen),
900 sizeof(use->rpu_uselen), "UseLen: %u", use->rpu_uselen);
901 proto_tree_add_text(opt_tree, tvb,
902 off + offsetof(struct rr_pco_use, rpu_keeplen),
903 sizeof(use->rpu_keeplen), "KeepLen: %u", use->rpu_keeplen);
904 tf = proto_tree_add_text(opt_tree, tvb,
905 flagoff = off + offsetof(struct rr_pco_use, rpu_ramask),
906 sizeof(use->rpu_ramask), "FlagMask: 0x%x", use->rpu_ramask);
907 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
908 flags = tvb_get_guint8(tvb, flagoff);
909 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
910 decode_boolean_bitfield(flags,
911 ICMP6_RR_PCOUSE_RAFLAGS_ONLINK, 8,
912 "Onlink", "Not onlink"));
913 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
914 decode_boolean_bitfield(flags,
915 ICMP6_RR_PCOUSE_RAFLAGS_AUTO, 8,
916 "Auto", "Not auto"));
917 tf = proto_tree_add_text(opt_tree, tvb,
918 flagoff = off + offsetof(struct rr_pco_use, rpu_raflags),
919 sizeof(use->rpu_raflags), "RAFlags: 0x%x", use->rpu_raflags);
920 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
921 flags = tvb_get_guint8(tvb, flagoff);
922 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
923 decode_boolean_bitfield(flags,
924 ICMP6_RR_PCOUSE_RAFLAGS_ONLINK, 8,
925 "Onlink", "Not onlink"));
926 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
927 decode_boolean_bitfield(flags,
928 ICMP6_RR_PCOUSE_RAFLAGS_AUTO, 8, "Auto", "Not auto"));
929 if (pntohl(&use->rpu_vltime) == 0xffffffff)
930 proto_tree_add_text(opt_tree, tvb,
931 off + offsetof(struct rr_pco_use, rpu_vltime),
932 sizeof(use->rpu_vltime), "Valid Lifetime: infinity");
934 proto_tree_add_text(opt_tree, tvb,
935 off + offsetof(struct rr_pco_use, rpu_vltime),
936 sizeof(use->rpu_vltime), "Valid Lifetime: %u",
937 pntohl(&use->rpu_vltime));
938 if (pntohl(&use->rpu_pltime) == 0xffffffff)
939 proto_tree_add_text(opt_tree, tvb,
940 off + offsetof(struct rr_pco_use, rpu_pltime),
941 sizeof(use->rpu_pltime), "Preferred Lifetime: infinity");
943 proto_tree_add_text(opt_tree, tvb,
944 off + offsetof(struct rr_pco_use, rpu_pltime),
945 sizeof(use->rpu_pltime), "Preferred Lifetime: %u",
946 pntohl(&use->rpu_pltime));
947 tf = proto_tree_add_text(opt_tree, tvb,
948 flagoff = off + offsetof(struct rr_pco_use, rpu_flags),
949 sizeof(use->rpu_flags), "Flags: 0x%08x",
950 pntohl(&use->rpu_flags));
951 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
952 flags = tvb_get_guint8(tvb, flagoff);
953 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
954 decode_boolean_bitfield(flags,
955 ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, 32,
956 "Decrement valid lifetime", "No decrement valid lifetime"));
957 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
958 decode_boolean_bitfield(flags,
959 ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, 32,
960 "Decrement preferred lifetime",
961 "No decrement preferred lifetime"));
962 proto_tree_add_text(opt_tree, tvb,
963 off + offsetof(struct rr_pco_use, rpu_prefix),
964 sizeof(use->rpu_prefix), "UsePrefix: %s",
965 ip6_to_str(&use->rpu_prefix));
972 dissect_icmpv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
974 proto_tree *icmp6_tree, *field_tree;
975 proto_item *ti, *tf = NULL;
976 struct icmp6_hdr icmp6_hdr, *dp;
977 struct icmp6_nodeinfo *ni = NULL;
978 char *codename, *typename;
979 char *colcodename, *coltypename;
981 guint length, reported_length;
984 guint16 cksum, computed_cksum;
988 if (check_col(pinfo->cinfo, COL_PROTOCOL))
989 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ICMPv6");
990 if (check_col(pinfo->cinfo, COL_INFO))
991 col_clear(pinfo->cinfo, COL_INFO);
994 tvb_memcpy(tvb, (guint8 *)&icmp6_hdr, offset, sizeof icmp6_hdr);
996 codename = typename = colcodename = coltypename = "Unknown";
998 switch (dp->icmp6_type) {
999 case ICMP6_DST_UNREACH:
1000 typename = coltypename = "Unreachable";
1001 switch (dp->icmp6_code) {
1002 case ICMP6_DST_UNREACH_NOROUTE:
1003 codename = colcodename = "Route unreachable";
1005 case ICMP6_DST_UNREACH_ADMIN:
1006 codename = colcodename = "Administratively prohibited";
1008 case ICMP6_DST_UNREACH_NOTNEIGHBOR:
1009 codename = colcodename = "Not a neighbor";
1011 case ICMP6_DST_UNREACH_ADDR:
1012 codename = colcodename = "Address unreachable";
1014 case ICMP6_DST_UNREACH_NOPORT:
1015 codename = colcodename = "Port unreachable";
1019 case ICMP6_PACKET_TOO_BIG:
1020 typename = coltypename = "Too big";
1021 codename = colcodename = NULL;
1023 case ICMP6_TIME_EXCEEDED:
1024 typename = coltypename = "Time exceeded";
1025 switch (dp->icmp6_code) {
1026 case ICMP6_TIME_EXCEED_TRANSIT:
1027 codename = colcodename = "In-transit";
1029 case ICMP6_TIME_EXCEED_REASSEMBLY:
1030 codename = colcodename = "Reassembly";
1034 case ICMP6_PARAM_PROB:
1035 typename = coltypename = "Parameter problem";
1036 switch (dp->icmp6_code) {
1037 case ICMP6_PARAMPROB_HEADER:
1038 codename = colcodename = "Header";
1040 case ICMP6_PARAMPROB_NEXTHEADER:
1041 codename = colcodename = "Next header";
1043 case ICMP6_PARAMPROB_OPTION:
1044 codename = colcodename = "Option";
1048 case ICMP6_ECHO_REQUEST:
1049 typename = coltypename = "Echo request";
1050 codename = colcodename = NULL;
1052 case ICMP6_ECHO_REPLY:
1053 typename = coltypename = "Echo reply";
1054 codename = colcodename = NULL;
1056 case ICMP6_MEMBERSHIP_QUERY:
1057 typename = coltypename = "Multicast listener query";
1058 codename = colcodename = NULL;
1060 case ICMP6_MEMBERSHIP_REPORT:
1061 typename = coltypename = "Multicast listener report";
1062 codename = colcodename = NULL;
1064 case ICMP6_MEMBERSHIP_REDUCTION:
1065 typename = coltypename = "Multicast listener done";
1066 codename = colcodename = NULL;
1068 case ND_ROUTER_SOLICIT:
1069 typename = coltypename = "Router solicitation";
1070 codename = colcodename = NULL;
1071 len = sizeof(struct nd_router_solicit);
1073 case ND_ROUTER_ADVERT:
1074 typename = coltypename = "Router advertisement";
1075 codename = colcodename = NULL;
1076 len = sizeof(struct nd_router_advert);
1078 case ND_NEIGHBOR_SOLICIT:
1079 typename = coltypename = "Neighbor solicitation";
1080 codename = colcodename = NULL;
1081 len = sizeof(struct nd_neighbor_solicit);
1083 case ND_NEIGHBOR_ADVERT:
1084 typename = coltypename = "Neighbor advertisement";
1085 codename = colcodename = NULL;
1086 len = sizeof(struct nd_neighbor_advert);
1089 typename = coltypename = "Redirect";
1090 codename = colcodename = NULL;
1091 len = sizeof(struct nd_redirect);
1093 case ICMP6_ROUTER_RENUMBERING:
1094 typename = coltypename = "Router renumbering";
1095 switch (dp->icmp6_code) {
1096 case ICMP6_ROUTER_RENUMBERING_COMMAND:
1097 codename = colcodename = "Command";
1099 case ICMP6_ROUTER_RENUMBERING_RESULT:
1100 codename = colcodename = "Result";
1102 case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
1103 codename = colcodename = "Sequence number reset";
1106 len = sizeof(struct icmp6_router_renum);
1108 case ICMP6_NI_QUERY:
1109 case ICMP6_NI_REPLY:
1110 ni = (struct icmp6_nodeinfo *)dp;
1111 if (ni->ni_type == ICMP6_NI_QUERY) {
1112 typename = coltypename = "Node information query";
1113 switch (ni->ni_code) {
1114 case ICMP6_NI_SUBJ_IPV6:
1115 codename = "Query subject = IPv6 addresses";
1117 case ICMP6_NI_SUBJ_FQDN:
1118 if (tvb_bytes_exist(tvb, offset, sizeof(*ni)))
1119 codename = "Query subject = DNS name";
1121 codename = "Query subject = empty";
1123 case ICMP6_NI_SUBJ_IPV4:
1124 codename = "Query subject = IPv4 addresses";
1128 typename = coltypename = "Node information reply";
1129 switch (ni->ni_code) {
1130 case ICMP6_NI_SUCCESS:
1131 codename = "Successful";
1133 case ICMP6_NI_REFUSED:
1134 codename = "Refused";
1136 case ICMP6_NI_UNKNOWN:
1137 codename = "Unknown query type";
1141 colcodename = val_to_str(pntohs(&ni->ni_qtype), names_nodeinfo_qtype,
1143 len = sizeof(struct icmp6_nodeinfo);
1147 if (check_col(pinfo->cinfo, COL_INFO)) {
1148 char typebuf[256], codebuf[256];
1150 if (coltypename && strcmp(coltypename, "Unknown") == 0) {
1151 snprintf(typebuf, sizeof(typebuf), "Unknown (0x%02x)",
1153 coltypename = typebuf;
1155 if (colcodename && strcmp(colcodename, "Unknown") == 0) {
1156 snprintf(codebuf, sizeof(codebuf), "Unknown (0x%02x)",
1158 colcodename = codebuf;
1161 col_add_fstr(pinfo->cinfo, COL_INFO, "%s (%s)", coltypename, colcodename);
1163 col_add_fstr(pinfo->cinfo, COL_INFO, "%s", coltypename);
1168 /* !!! specify length */
1169 ti = proto_tree_add_item(tree, proto_icmpv6, tvb, offset, len, FALSE);
1170 icmp6_tree = proto_item_add_subtree(ti, ett_icmpv6);
1172 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_type, tvb,
1173 offset + offsetof(struct icmp6_hdr, icmp6_type), 1,
1175 "Type: %u (%s)", dp->icmp6_type, typename);
1177 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_code, tvb,
1178 offset + offsetof(struct icmp6_hdr, icmp6_code), 1,
1180 "Code: %u (%s)", dp->icmp6_code, codename);
1182 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_code, tvb,
1183 offset + offsetof(struct icmp6_hdr, icmp6_code), 1,
1185 "Code: %u", dp->icmp6_code);
1187 cksum = (guint16)g_htons(dp->icmp6_cksum);
1188 length = tvb_length(tvb);
1189 reported_length = tvb_reported_length(tvb);
1190 if (!pinfo->fragmented && length >= reported_length) {
1191 /* The packet isn't part of a fragmented datagram and isn't
1192 truncated, so we can checksum it. */
1194 /* Set up the fields of the pseudo-header. */
1195 cksum_vec[0].ptr = pinfo->src.data;
1196 cksum_vec[0].len = pinfo->src.len;
1197 cksum_vec[1].ptr = pinfo->dst.data;
1198 cksum_vec[1].len = pinfo->dst.len;
1199 cksum_vec[2].ptr = (const guint8 *)&phdr;
1200 phdr[0] = g_htonl(tvb_reported_length(tvb));
1201 phdr[1] = g_htonl(IP_PROTO_ICMPV6);
1202 cksum_vec[2].len = 8;
1203 cksum_vec[3].len = tvb_reported_length(tvb);
1204 cksum_vec[3].ptr = tvb_get_ptr(tvb, offset, cksum_vec[3].len);
1205 computed_cksum = in_cksum(cksum_vec, 4);
1206 if (computed_cksum == 0) {
1207 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_checksum,
1209 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1211 "Checksum: 0x%04x (correct)", cksum);
1213 proto_tree_add_boolean_hidden(icmp6_tree, hf_icmpv6_checksum_bad,
1215 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1217 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_checksum,
1219 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1221 "Checksum: 0x%04x (incorrect, should be 0x%04x)",
1222 cksum, in_cksum_shouldbe(cksum, computed_cksum));
1225 proto_tree_add_uint(icmp6_tree, hf_icmpv6_checksum, tvb,
1226 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1231 switch (dp->icmp6_type) {
1232 case ICMP6_DST_UNREACH:
1233 case ICMP6_TIME_EXCEEDED:
1234 dissect_contained_icmpv6(tvb, offset + sizeof(*dp), pinfo,
1237 case ICMP6_PACKET_TOO_BIG:
1238 proto_tree_add_text(icmp6_tree, tvb,
1239 offset + offsetof(struct icmp6_hdr, icmp6_mtu), 4,
1240 "MTU: %u", pntohl(&dp->icmp6_mtu));
1241 dissect_contained_icmpv6(tvb, offset + sizeof(*dp), pinfo,
1244 case ICMP6_PARAM_PROB:
1245 proto_tree_add_text(icmp6_tree, tvb,
1246 offset + offsetof(struct icmp6_hdr, icmp6_pptr), 4,
1247 "Problem pointer: 0x%04x", pntohl(&dp->icmp6_pptr));
1248 dissect_contained_icmpv6(tvb, offset + sizeof(*dp), pinfo,
1251 case ICMP6_ECHO_REQUEST:
1252 case ICMP6_ECHO_REPLY:
1253 proto_tree_add_text(icmp6_tree, tvb,
1254 offset + offsetof(struct icmp6_hdr, icmp6_id), 2,
1255 "ID: 0x%04x", (guint16)g_ntohs(dp->icmp6_id));
1256 proto_tree_add_text(icmp6_tree, tvb,
1257 offset + offsetof(struct icmp6_hdr, icmp6_seq), 2,
1258 "Sequence: 0x%04x", (guint16)g_ntohs(dp->icmp6_seq));
1259 next_tvb = tvb_new_subset(tvb, offset + sizeof(*dp), -1, -1);
1260 call_dissector(data_handle,next_tvb, pinfo, icmp6_tree);
1262 case ICMP6_MEMBERSHIP_QUERY:
1263 case ICMP6_MEMBERSHIP_REPORT:
1264 case ICMP6_MEMBERSHIP_REDUCTION:
1265 proto_tree_add_text(icmp6_tree, tvb,
1266 offset + offsetof(struct icmp6_hdr, icmp6_maxdelay), 2,
1267 "Maximum response delay: %u",
1268 (guint16)g_ntohs(dp->icmp6_maxdelay));
1269 proto_tree_add_text(icmp6_tree, tvb, offset + sizeof(*dp), 16,
1270 "Multicast Address: %s",
1271 ip6_to_str((struct e_in6_addr *)(tvb_get_ptr(tvb, offset + sizeof *dp, sizeof (struct e_in6_addr)))));
1273 case ND_ROUTER_SOLICIT:
1274 dissect_icmpv6opt(tvb, offset + sizeof(*dp), pinfo, icmp6_tree);
1276 case ND_ROUTER_ADVERT:
1278 struct nd_router_advert nd_router_advert, *ra;
1282 ra = &nd_router_advert;
1283 tvb_memcpy(tvb, (guint8 *)ra, offset, sizeof *ra);
1284 proto_tree_add_text(icmp6_tree, tvb,
1285 offset + offsetof(struct nd_router_advert, nd_ra_curhoplimit),
1286 1, "Cur hop limit: %u", ra->nd_ra_curhoplimit);
1288 flagoff = offset + offsetof(struct nd_router_advert, nd_ra_flags_reserved);
1289 ra_flags = tvb_get_guint8(tvb, flagoff);
1290 tf = proto_tree_add_text(icmp6_tree, tvb, flagoff, 1, "Flags: 0x%02x", ra_flags);
1291 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1292 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1293 decode_boolean_bitfield(ra_flags,
1294 ND_RA_FLAG_MANAGED, 8, "Managed", "Not managed"));
1295 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1296 decode_boolean_bitfield(ra_flags,
1297 ND_RA_FLAG_OTHER, 8, "Other", "Not other"));
1298 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1299 decode_boolean_bitfield(ra_flags,
1300 ND_RA_FLAG_HOME_AGENT, 8,
1301 "Home Agent", "Not Home Agent"));
1302 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1303 decode_enumerated_bitfield(ra_flags, ND_RA_FLAG_RTPREF_MASK, 8,
1304 names_router_pref, "Router preference: %s"));
1305 proto_tree_add_text(icmp6_tree, tvb,
1306 offset + offsetof(struct nd_router_advert, nd_ra_router_lifetime),
1307 2, "Router lifetime: %u",
1308 (guint16)g_ntohs(ra->nd_ra_router_lifetime));
1309 proto_tree_add_text(icmp6_tree, tvb,
1310 offset + offsetof(struct nd_router_advert, nd_ra_reachable), 4,
1311 "Reachable time: %u", pntohl(&ra->nd_ra_reachable));
1312 proto_tree_add_text(icmp6_tree, tvb,
1313 offset + offsetof(struct nd_router_advert, nd_ra_retransmit), 4,
1314 "Retrans time: %u", pntohl(&ra->nd_ra_retransmit));
1315 dissect_icmpv6opt(tvb, offset + sizeof(struct nd_router_advert), pinfo, icmp6_tree);
1318 case ND_NEIGHBOR_SOLICIT:
1320 struct nd_neighbor_solicit nd_neighbor_solicit, *ns;
1322 ns = &nd_neighbor_solicit;
1323 tvb_memcpy(tvb, (guint8 *)ns, offset, sizeof *ns);
1324 proto_tree_add_text(icmp6_tree, tvb,
1325 offset + offsetof(struct nd_neighbor_solicit, nd_ns_target), 16,
1328 get_hostname6(&ns->nd_ns_target),
1332 ip6_to_str(&ns->nd_ns_target));
1334 dissect_icmpv6opt(tvb, offset + sizeof(*ns), pinfo, icmp6_tree);
1337 case ND_NEIGHBOR_ADVERT:
1339 int flagoff, targetoff;
1341 struct e_in6_addr na_target;
1343 flagoff = offset + offsetof(struct nd_neighbor_advert, nd_na_flags_reserved);
1344 na_flags = tvb_get_ntohl(tvb, flagoff);
1346 tf = proto_tree_add_text(icmp6_tree, tvb, flagoff, 4, "Flags: 0x%08x", na_flags);
1347 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1348 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
1349 decode_boolean_bitfield(na_flags,
1350 ND_NA_FLAG_ROUTER, 32, "Router", "Not router"));
1351 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
1352 decode_boolean_bitfield(na_flags,
1353 ND_NA_FLAG_SOLICITED, 32, "Solicited", "Not adverted"));
1354 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
1355 decode_boolean_bitfield(na_flags,
1356 ND_NA_FLAG_OVERRIDE, 32, "Override", "Not override"));
1358 targetoff = offset + offsetof(struct nd_neighbor_advert, nd_na_target);
1359 tvb_memcpy(tvb, (guint8 *)&na_target, targetoff, sizeof na_target);
1360 proto_tree_add_text(icmp6_tree, tvb, targetoff, 16,
1363 get_hostname6(&na_target),
1367 ip6_to_str(&na_target));
1369 dissect_icmpv6opt(tvb, offset + sizeof(struct nd_neighbor_advert), pinfo, icmp6_tree);
1374 struct nd_redirect nd_redirect, *rd;
1377 tvb_memcpy(tvb, (guint8 *)rd, offset, sizeof *rd);
1378 proto_tree_add_text(icmp6_tree, tvb,
1379 offset + offsetof(struct nd_redirect, nd_rd_target), 16,
1382 get_hostname6(&rd->nd_rd_target),
1386 ip6_to_str(&rd->nd_rd_target));
1388 proto_tree_add_text(icmp6_tree, tvb,
1389 offset + offsetof(struct nd_redirect, nd_rd_dst), 16,
1391 "Destination: %s (%s)",
1392 get_hostname6(&rd->nd_rd_dst),
1396 ip6_to_str(&rd->nd_rd_dst));
1398 dissect_icmpv6opt(tvb, offset + sizeof(*rd), pinfo, icmp6_tree);
1401 case ICMP6_ROUTER_RENUMBERING:
1402 dissect_rrenum(tvb, offset, pinfo, icmp6_tree);
1404 case ICMP6_NI_QUERY:
1405 case ICMP6_NI_REPLY:
1406 ni = (struct icmp6_nodeinfo *)dp;
1407 proto_tree_add_text(icmp6_tree, tvb,
1408 offset + offsetof(struct icmp6_nodeinfo, ni_qtype),
1409 sizeof(ni->ni_qtype),
1410 "Query type: 0x%04x (%s)", pntohs(&ni->ni_qtype),
1411 val_to_str(pntohs(&ni->ni_qtype), names_nodeinfo_qtype,
1413 dissect_nodeinfo(tvb, offset, pinfo, icmp6_tree);
1416 next_tvb = tvb_new_subset(tvb, offset + sizeof(*dp), -1, -1);
1417 call_dissector(data_handle,next_tvb, pinfo, tree);
1424 proto_register_icmpv6(void)
1426 static hf_register_info hf[] = {
1428 { "Type", "icmpv6.type", FT_UINT8, BASE_DEC, NULL, 0x0,
1431 { "Code", "icmpv6.code", FT_UINT8, BASE_DEC, NULL, 0x0,
1433 { &hf_icmpv6_checksum,
1434 { "Checksum", "icmpv6.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
1436 { &hf_icmpv6_checksum_bad,
1437 { "Bad Checksum", "icmpv6.checksum_bad", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1440 static gint *ett[] = {
1445 &ett_nodeinfo_subject4,
1446 &ett_nodeinfo_subject6,
1447 &ett_nodeinfo_node4,
1448 &ett_nodeinfo_node6,
1449 &ett_nodeinfo_nodebitmap,
1450 &ett_nodeinfo_nodedns,
1453 proto_icmpv6 = proto_register_protocol("Internet Control Message Protocol v6",
1454 "ICMPv6", "icmpv6");
1455 proto_register_field_array(proto_icmpv6, hf, array_length(hf));
1456 proto_register_subtree_array(ett, array_length(ett));
1460 proto_reg_handoff_icmpv6(void)
1462 dissector_handle_t icmpv6_handle;
1464 icmpv6_handle = create_dissector_handle(dissect_icmpv6, proto_icmpv6);
1465 dissector_add("ip.proto", IP_PROTO_ICMPV6, icmpv6_handle);
1468 * Get a handle for the IPv6 dissector.
1470 ipv6_handle = find_dissector("ipv6");
1471 data_handle = find_dissector("data");