2 * Routines for ICMPv6 packet disassembly
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
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 * FMIPv6 support added by Martin Andre <andre@clarinet.u-strasbg.fr>
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version 2
19 * of the License, or (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
46 #include <epan/packet.h>
47 #include "packet-ipv6.h"
48 #include "packet-dns.h"
49 #include <epan/in_cksum.h>
50 #include <epan/addr_resolv.h>
51 #include <epan/ipproto.h>
52 #include <epan/emem.h>
55 #define offsetof(type, member) ((size_t)(&((type *)0)->member))
59 * See, under http://www.ietf.org/internet-drafts/
61 * draft-ietf-mobileip-ipv6-15.txt
65 * draft-ietf-ipngwg-icmp-name-lookups-08.txt
69 * draft-ietf-mobileip-hmipv6-05.txt
76 static int proto_icmpv6 = -1;
77 static int hf_icmpv6_type = -1;
78 static int hf_icmpv6_code = -1;
79 static int hf_icmpv6_checksum = -1;
80 static int hf_icmpv6_checksum_bad = -1;
81 static int hf_icmpv6_haad_ha_addrs = -1;
83 static gint ett_icmpv6 = -1;
84 static gint ett_icmpv6opt = -1;
85 static gint ett_icmpv6flag = -1;
86 static gint ett_nodeinfo_flag = -1;
87 static gint ett_nodeinfo_subject4 = -1;
88 static gint ett_nodeinfo_subject6 = -1;
89 static gint ett_nodeinfo_node4 = -1;
90 static gint ett_nodeinfo_node6 = -1;
91 static gint ett_nodeinfo_nodebitmap = -1;
92 static gint ett_nodeinfo_nodedns = -1;
93 static gint ett_multicastRR = -1;
95 static dissector_handle_t ipv6_handle;
96 static dissector_handle_t data_handle;
98 static const value_string names_nodeinfo_qtype[] = {
99 { NI_QTYPE_NOOP, "NOOP" },
100 { NI_QTYPE_SUPTYPES, "Supported query types" },
101 { NI_QTYPE_DNSNAME, "DNS name" },
102 { NI_QTYPE_NODEADDR, "Node addresses" },
103 { NI_QTYPE_IPV4ADDR, "IPv4 node addresses" },
107 static const value_string names_rrenum_matchcode[] = {
108 { RPM_PCO_ADD, "Add" },
109 { RPM_PCO_CHANGE, "Change" },
110 { RPM_PCO_SETGLOBAL, "Set Global" },
114 static const value_string names_router_pref[] = {
115 { ND_RA_FLAG_RTPREF_HIGH, "High" },
116 { ND_RA_FLAG_RTPREF_MEDIUM, "Medium" },
117 { ND_RA_FLAG_RTPREF_LOW, "Low" },
118 { ND_RA_FLAG_RTPREF_RSV, "Reserved" },
122 static const value_string names_fmip6_prrtadv_code[] = {
123 { FMIP6_PRRTADV_MNTUP, "MN should use AP-ID, AR-info tuple" },
124 { FMIP6_PRRTADV_NI_HOVER, "Network Initiated Handover trigger" },
125 { FMIP6_PRRTADV_NORTINFO, "No new router information" },
126 { FMIP6_PRRTADV_LIMRTINFO, "Limited new router information" },
127 { FMIP6_PRRTADV_UNSOL, "Unsolicited" },
131 static const value_string names_fmip6_hi_code[] = {
132 { FMIP6_HI_PCOA, "FBU sent from previous link" },
133 { FMIP6_HI_NOTPCOA, "FBU sent from new link" },
137 static const value_string names_fmip6_hack_code[] = {
138 { FMIP6_HACK_VALID, "Handover Accepted, NCoA valid" },
139 { FMIP6_HACK_INVALID, "Handover Accepted, NCoA not valid" },
140 { FMIP6_HACK_INUSE, "Handover Accepted, NCoA in use" },
141 { FMIP6_HACK_ASSIGNED, "Handover Accepted, NCoA assigned" },
142 { FMIP6_HACK_NOTASSIGNED, "Handover Accepted, NCoA not assigned" },
143 { FMIP6_HACK_NOTACCEPTED, "Handover Not Accepted, reason unspecified" },
144 { FMIP6_HACK_PROHIBITED, "Administratively prohibited" },
145 { FMIP6_HACK_INSUFFICIENT, "Insufficient resources" },
149 static const value_string names_fmip6_ip_addr_opt_code[] = {
150 { FMIP6_OPT_IP_ADDRESS_OPTCODE_PCOA, "Old Care-of Address" },
151 { FMIP6_OPT_IP_ADDRESS_OPTCODE_NCOA, "New Care-of Address" },
152 { FMIP6_OPT_IP_ADDRESS_OPTCODE_NAR, "NAR's IP address" },
156 static const value_string names_fmip6_lla_opt_code[] = {
157 { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_WILDCARD, "Wildcard" },
158 { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_NAP, "Link-layer Address of the New Access Point" },
159 { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_MN, "Link-layer Address of the MN" },
160 { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_NAR, "Link-layer Address of the NAR" },
161 { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_SRC, "Link-layer Address of the source" },
162 { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_CURROUTER, "The AP belongs to the current interface of the router" },
163 { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_NOPREFIX, "No prefix information available" },
164 { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_NOSUPPORT, "No fast handovers support available" },
168 static const value_string names_fmip6_naack_opt_status[] = {
169 { FMIP6_OPT_NEIGHBOR_ADV_ACK_STATUS_INVALID, "New CoA is invalid" },
170 { FMIP6_OPT_NEIGHBOR_ADV_ACK_STATUS_INVALID_NEW, "New CoA is invalid, use the supplied CoA" },
171 { FMIP6_OPT_NEIGHBOR_ADV_ACK_STATUS_UNRECOGNIZED, "LLA is unrecognized" },
176 dissect_contained_icmpv6(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
178 gboolean save_in_error_pkt;
181 /* Save the current value of the "we're inside an error packet"
182 flag, and set that flag; subdissectors may treat packets
183 that are the payload of error packets differently from
185 save_in_error_pkt = pinfo->in_error_pkt;
186 pinfo->in_error_pkt = TRUE;
188 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
190 /* tiny sanity check */
191 if ((tvb_get_guint8(tvb, offset) & 0xf0) == 0x60) {
192 /* The contained packet is an IPv6 datagram; dissect it. */
193 call_dissector(ipv6_handle, next_tvb, pinfo, tree);
195 call_dissector(data_handle,next_tvb, pinfo, tree);
197 /* Restore the "we're inside an error packet" flag. */
198 pinfo->in_error_pkt = save_in_error_pkt;
202 dissect_icmpv6ndopt(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
204 proto_tree *icmp6opt_tree, *field_tree;
206 struct nd_opt_hdr nd_opt_hdr, *opt;
208 const char *typename;
209 static const guint8 nd_redirect_reserved[6] = {0, 0, 0, 0, 0, 0};
210 guint8 nd_redirect_res[6];
216 if ((int)tvb_reported_length(tvb) <= offset)
217 return; /* No more options left */
220 tvb_memcpy(tvb, (guint8 *)opt, offset, sizeof *opt);
221 len = opt->nd_opt_len << 3;
223 /* !!! specify length */
224 ti = proto_tree_add_text(tree, tvb, offset, len, "ICMPv6 options");
225 icmp6opt_tree = proto_item_add_subtree(ti, ett_icmpv6opt);
228 proto_tree_add_text(icmp6opt_tree, tvb,
229 offset + offsetof(struct nd_opt_hdr, nd_opt_len), 1,
230 "Invalid option length: %u",
232 return; /* we must not try to decode this */
235 switch (opt->nd_opt_type) {
236 case ND_OPT_SOURCE_LINKADDR:
237 typename = "Source link-layer address";
239 case ND_OPT_TARGET_LINKADDR:
240 typename = "Target link-layer address";
242 case ND_OPT_PREFIX_INFORMATION:
243 typename = "Prefix information";
245 case ND_OPT_REDIRECTED_HEADER:
246 typename = "Redirected header";
251 case ND_OPT_ADVINTERVAL:
252 typename = "Advertisement Interval";
254 case ND_OPT_HOMEAGENT_INFO:
255 typename = "Home Agent Information";
258 typename = "HMIPv6 MAP option";
260 case FMIP6_OPT_NEIGHBOR_ADV_ACK:
261 typename = "Neighbor Advertisement Acknowledgment";
264 typename = "Unknown";
268 proto_tree_add_text(icmp6opt_tree, tvb,
269 offset + offsetof(struct nd_opt_hdr, nd_opt_type), 1,
270 "Type: %u (%s)", opt->nd_opt_type, typename);
271 proto_tree_add_text(icmp6opt_tree, tvb,
272 offset + offsetof(struct nd_opt_hdr, nd_opt_len), 1,
273 "Length: %u bytes (%u)", opt->nd_opt_len << 3, opt->nd_opt_len);
276 switch (opt->nd_opt_type) {
277 case ND_OPT_SOURCE_LINKADDR:
278 case ND_OPT_TARGET_LINKADDR:
282 p = offset + sizeof(*opt);
283 len = (opt->nd_opt_len << 3) - sizeof(*opt);
284 proto_tree_add_text(icmp6opt_tree, tvb,
285 offset + sizeof(*opt), len, "Link-layer address: %s",
286 bytestring_to_str(tvb_get_ptr(tvb, p, len), len, ':'));
289 case ND_OPT_PREFIX_INFORMATION:
291 struct nd_opt_prefix_info nd_opt_prefix_info, *pi;
294 pi = &nd_opt_prefix_info;
295 tvb_memcpy(tvb, (guint8 *)pi, offset, sizeof *pi);
296 proto_tree_add_text(icmp6opt_tree, tvb,
297 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_prefix_len),
298 1, "Prefix length: %u", pi->nd_opt_pi_prefix_len);
300 flagoff = offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_flags_reserved);
301 tf = proto_tree_add_text(icmp6opt_tree, tvb, flagoff, 1, "Flags: 0x%02x",
302 tvb_get_guint8(tvb, offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_flags_reserved)));
303 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
304 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
305 decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
306 ND_OPT_PI_FLAG_ONLINK, 8, "Onlink", "Not onlink"));
307 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
308 decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
309 ND_OPT_PI_FLAG_AUTO, 8, "Auto", "Not auto"));
310 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
311 decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
312 ND_OPT_PI_FLAG_ROUTER, 8,
313 "Router Address", "Not router address"));
314 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
315 decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
316 ND_OPT_PI_FLAG_SITEPREF, 8,
317 "Site prefix", "Not site prefix"));
318 proto_tree_add_text(icmp6opt_tree, tvb,
319 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_valid_time),
320 4, "Valid lifetime: 0x%08x",
321 pntohl(&pi->nd_opt_pi_valid_time));
322 proto_tree_add_text(icmp6opt_tree, tvb,
323 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_preferred_time),
324 4, "Preferred lifetime: 0x%08x",
325 pntohl(&pi->nd_opt_pi_preferred_time));
326 proto_tree_add_text(icmp6opt_tree, tvb,
327 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_prefix),
328 16, "Prefix: %s", ip6_to_str(&pi->nd_opt_pi_prefix));
331 case ND_OPT_REDIRECTED_HEADER:
332 tvb_memcpy(tvb, (guint8 *)&nd_redirect_res, offset + 2, 6);
333 if (memcmp(nd_redirect_res, nd_redirect_reserved, 6) == 0)
334 proto_tree_add_text(icmp6opt_tree, tvb,
335 offset + 2, 6, "Reserved: 0 (correct)");
337 proto_tree_add_text(icmp6opt_tree, tvb,
338 offset +2, 6, "Reserved: MUST be 0 (incorrect!)");
339 proto_tree_add_text(icmp6opt_tree, tvb,
340 offset + 8, (opt->nd_opt_len << 3) - 8, "Redirected packet");
341 dissect_contained_icmpv6(tvb, offset + 8, pinfo, icmp6opt_tree);
344 proto_tree_add_text(icmp6opt_tree, tvb,
345 offset + offsetof(struct nd_opt_mtu, nd_opt_mtu_mtu), 4,
346 "MTU: %u", tvb_get_ntohl(tvb, offset + offsetof(struct nd_opt_mtu, nd_opt_mtu_mtu)));
348 case ND_OPT_ADVINTERVAL:
349 proto_tree_add_text(icmp6opt_tree, tvb,
350 offset + offsetof(struct nd_opt_adv_int, nd_opt_adv_int_advint), 4,
351 "Advertisement Interval: %u",
352 tvb_get_ntohl(tvb, offset + offsetof(struct nd_opt_adv_int, nd_opt_adv_int_advint)));
354 case ND_OPT_HOMEAGENT_INFO:
356 struct nd_opt_ha_info pibuf, *pi;
359 tvb_memcpy(tvb, (guint8 *)pi, offset, sizeof *pi);
360 proto_tree_add_text(icmp6opt_tree, tvb,
361 offset + offsetof(struct nd_opt_ha_info, nd_opt_ha_info_ha_pref),
362 2, "Home Agent Preference: %d",
363 (gint16)pntohs(&pi->nd_opt_ha_info_ha_pref));
364 proto_tree_add_text(icmp6opt_tree, tvb,
365 offset + offsetof(struct nd_opt_ha_info, nd_opt_ha_info_ha_life),
366 2, "Home Agent Lifetime: %u",
367 pntohs(&pi->nd_opt_ha_info_ha_life));
372 struct nd_opt_map_info mapbuf, *map;
376 tvb_memcpy(tvb, (guint8 *)map, offset, sizeof *map);
377 proto_tree_add_text(icmp6opt_tree, tvb,
378 offset + offsetof(struct nd_opt_map_info, nd_opt_map_dist_and_pref),
379 1, "Distance: %u", (map->nd_opt_map_dist_and_pref >> 4));
380 proto_tree_add_text(icmp6opt_tree, tvb,
381 offset + offsetof(struct nd_opt_map_info, nd_opt_map_dist_and_pref),
382 1, "Preference: %u", (map->nd_opt_map_dist_and_pref & 0x0F));
383 flagoff = offset + offsetof(struct nd_opt_map_info,
385 tf = proto_tree_add_text(icmp6opt_tree, tvb, flagoff, 1,
387 tvb_get_guint8(tvb, offset + offsetof(struct nd_opt_map_info,
389 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
390 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
391 decode_boolean_bitfield(map->nd_opt_map_flags,
392 ND_OPT_MAP_FLAG_R, 8, "R", "No R"));
393 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
394 decode_boolean_bitfield(map->nd_opt_map_flags,
395 ND_OPT_MAP_FLAG_M, 8, "M", "No M"));
396 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
397 decode_boolean_bitfield(map->nd_opt_map_flags,
398 ND_OPT_MAP_FLAG_I, 8, "I", "No I"));
399 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
400 decode_boolean_bitfield(map->nd_opt_map_flags,
401 ND_OPT_MAP_FLAG_T, 8, "T", "No T"));
402 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
403 decode_boolean_bitfield(map->nd_opt_map_flags,
404 ND_OPT_MAP_FLAG_P, 8, "P", "No P"));
405 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
406 decode_boolean_bitfield(map->nd_opt_map_flags,
407 ND_OPT_MAP_FLAG_V, 8, "V", "No V"));
408 proto_tree_add_text(icmp6opt_tree, tvb,
409 offset + offsetof(struct nd_opt_map_info, nd_opt_map_lifetime),
410 4, "Lifetime: %u", pntohl(&map->nd_opt_map_lifetime));
412 proto_tree_add_text(icmp6opt_tree, tvb,
413 offset + offsetof(struct nd_opt_map_info, nd_opt_map_address), 16,
415 "Address of MAP: %s (%s)",
416 get_hostname6(&map->nd_opt_map_address),
418 "Address of MAP: %s",
420 ip6_to_str(&map->nd_opt_map_address));
423 case ND_OPT_ROUTE_INFO:
425 struct nd_opt_route_info ribuf, *ri;
426 struct e_in6_addr in6;
431 tvb_memcpy(tvb, (guint8 *)ri, offset, sizeof *ri);
432 memset(&in6, 0, sizeof(in6));
433 switch (ri->nd_opt_rti_len) {
438 tvb_memcpy(tvb, (guint8 *)&in6, offset + sizeof(*ri), l = 8);
441 tvb_memcpy(tvb, (guint8 *)&in6, offset + sizeof(*ri), l = 16);
448 proto_tree_add_text(icmp6opt_tree, tvb,
449 offset + offsetof(struct nd_opt_route_info, nd_opt_rti_prefixlen),
450 1, "Prefix length: %u", ri->nd_opt_rti_prefixlen);
451 tf = proto_tree_add_text(icmp6opt_tree, tvb,
452 offset + offsetof(struct nd_opt_route_info, nd_opt_rti_flags),
453 1, "Flags: 0x%02x", ri->nd_opt_rti_flags);
454 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
455 proto_tree_add_text(field_tree, tvb,
456 offset + offsetof(struct nd_opt_route_info, nd_opt_rti_flags),
458 decode_enumerated_bitfield(ri->nd_opt_rti_flags,
459 ND_RA_FLAG_RTPREF_MASK, 8, names_router_pref,
460 "Router preference: %s"));
461 lifetime = pntohl(&ri->nd_opt_rti_lifetime);
462 if (lifetime == 0xffffffff)
463 proto_tree_add_text(icmp6opt_tree, tvb,
464 offset + offsetof(struct nd_opt_route_info, nd_opt_rti_lifetime),
465 sizeof(ri->nd_opt_rti_lifetime), "Lifetime: infinity");
467 proto_tree_add_text(icmp6opt_tree, tvb,
468 offset + offsetof(struct nd_opt_route_info, nd_opt_rti_lifetime),
469 sizeof(ri->nd_opt_rti_lifetime), "Lifetime: %u", lifetime);
470 proto_tree_add_text(icmp6opt_tree, tvb,
471 offset + sizeof(*ri), l, "Prefix: %s", ip6_to_str(&in6));
473 proto_tree_add_text(icmp6opt_tree, tvb,
474 offset + offsetof(struct nd_opt_hdr, nd_opt_len), 1,
475 "Invalid option length: %u", opt->nd_opt_len);
480 case FMIP6_OPT_NEIGHBOR_ADV_ACK:
482 struct fmip6_opt_neighbor_advertisement_ack fmip6_opt_neighbor_advertisement_ack, *opt_naack;
483 struct e_in6_addr in6;
485 opt_naack = &fmip6_opt_neighbor_advertisement_ack;
486 tvb_memcpy(tvb, (guint8 *)opt_naack, offset, sizeof *opt_naack);
488 proto_tree_add_text(icmp6opt_tree, tvb,
489 offset + offsetof(struct fmip6_opt_neighbor_advertisement_ack, fmip6_opt_optcode),
490 1, "Option-Code: %u",
491 opt_naack->fmip6_opt_optcode);
493 proto_tree_add_text(icmp6opt_tree, tvb,
494 offset + offsetof(struct fmip6_opt_neighbor_advertisement_ack, fmip6_opt_status),
496 val_to_str(opt_naack->fmip6_opt_status, names_fmip6_naack_opt_status, "Unknown"));
498 if (opt_naack->fmip6_opt_len == 3)
500 tvb_memcpy(tvb, (guint8 *)&in6, offset + sizeof(*opt_naack), 16);
501 proto_tree_add_text(icmp6opt_tree, tvb,
502 offset + sizeof(*opt_naack),
503 16, "New Care-of Address: %s",
511 offset += (opt->nd_opt_len << 3);
516 dissect_icmpv6fmip6opt(tvbuff_t *tvb, int offset, proto_tree *tree)
518 proto_tree *icmp6opt_tree;
520 struct fmip6_opt_hdr fmip6_opt_hdr, *opt;
528 if ((int)tvb_reported_length(tvb) <= offset)
529 return; /* No more options left */
531 opt = &fmip6_opt_hdr;
532 tvb_memcpy(tvb, (guint8 *)opt, offset, sizeof *opt);
533 len = opt->fmip6_opt_len << 3;
535 /* !!! specify length */
536 ti = proto_tree_add_text(tree, tvb, offset, len, "ICMPv6 options");
537 icmp6opt_tree = proto_item_add_subtree(ti, ett_icmpv6opt);
540 proto_tree_add_text(icmp6opt_tree, tvb,
541 offset + offsetof(struct fmip6_opt_hdr, fmip6_opt_len), 1,
542 "Invalid option length: %u",
544 return; /* we must not try to decode this */
547 switch (opt->fmip6_opt_type) {
548 case FMIP6_OPT_IP_ADDRESS:
549 typename = "IP Address";
551 case FMIP6_OPT_NEW_ROUTER_PREFIX_INFO:
552 typename = "New Router Prefix Information";
554 case FMIP6_OPT_LINK_LAYER_ADDRESS:
555 typename = "Link-layer Address";
558 typename = "Unknown";
562 proto_tree_add_text(icmp6opt_tree, tvb,
563 offset + offsetof(struct fmip6_opt_hdr, fmip6_opt_type), 1,
564 "Type: %u (%s)", opt->fmip6_opt_type, typename);
565 proto_tree_add_text(icmp6opt_tree, tvb,
566 offset + offsetof(struct fmip6_opt_hdr, fmip6_opt_len), 1,
567 "Length: %u bytes (%u)", opt->fmip6_opt_len << 3, opt->fmip6_opt_len);
570 switch (opt->fmip6_opt_type) {
571 case FMIP6_OPT_IP_ADDRESS:
573 struct fmip6_opt_ip_address fmip6_opt_ip_address, *opt_ip;
575 opt_ip = &fmip6_opt_ip_address;
576 tvb_memcpy(tvb, (guint8 *)opt_ip, offset, sizeof *opt_ip);
578 proto_tree_add_text(icmp6opt_tree, tvb,
579 offset + offsetof(struct fmip6_opt_hdr, fmip6_opt_optcode), 1, "Option-Code: %s",
580 val_to_str(opt->fmip6_opt_optcode, names_fmip6_ip_addr_opt_code, "Unknown"));
582 proto_tree_add_text(icmp6opt_tree, tvb,
583 offset + offsetof(struct fmip6_opt_ip_address, fmip6_opt_prefix_len),
584 1, "Prefix length: %u", opt_ip->fmip6_opt_prefix_len);
586 proto_tree_add_text(icmp6opt_tree, tvb,
587 offset + offsetof(struct fmip6_opt_ip_address, fmip6_opt_ip6_address),
588 16, "IPv6 Address: %s",
589 ip6_to_str(&opt_ip->fmip6_opt_ip6_address));
592 case FMIP6_OPT_NEW_ROUTER_PREFIX_INFO:
594 struct fmip6_opt_new_router_prefix_info fmip6_opt_new_router_prefix_info, *opt_nr;
596 opt_nr = &fmip6_opt_new_router_prefix_info;
597 tvb_memcpy(tvb, (guint8 *)opt_nr, offset, sizeof *opt_nr);
599 proto_tree_add_text(icmp6opt_tree, tvb,
600 offset + offsetof(struct fmip6_opt_hdr, fmip6_opt_optcode), 1, "Option-Code: %u",
601 opt->fmip6_opt_optcode);
603 proto_tree_add_text(icmp6opt_tree, tvb,
604 offset + offsetof(struct fmip6_opt_new_router_prefix_info, fmip6_opt_prefix_len),
605 1, "Prefix length: %u", opt_nr->fmip6_opt_prefix_len);
607 proto_tree_add_text(icmp6opt_tree, tvb,
608 offset + offsetof(struct fmip6_opt_new_router_prefix_info, fmip6_opt_prefix),
610 ip6_to_str(&opt_nr->fmip6_opt_prefix));
614 case FMIP6_OPT_LINK_LAYER_ADDRESS:
618 p = offset + sizeof(*opt);
619 proto_tree_add_text(icmp6opt_tree, tvb,
620 offset + offsetof(struct fmip6_opt_hdr, fmip6_opt_optcode), 1, "Option-Code: %s",
621 val_to_str(opt->fmip6_opt_optcode, names_fmip6_lla_opt_code, "Unknown"));
622 len = (opt->fmip6_opt_len << 3) - sizeof(*opt);
623 proto_tree_add_text(icmp6opt_tree, tvb,
624 offset + sizeof(*opt), len, "Link-layer address: %s",
625 bytestring_to_str(tvb_get_ptr(tvb, p, len), len, ':'));
630 offset += (opt->fmip6_opt_len << 3);
635 * draft-ietf-ipngwg-icmp-name-lookups-07.txt
636 * Note that the packet format was changed several times in the past.
640 bitrange0(guint32 v, int s, char *buf, int buflen)
656 ep = buf + buflen - 1;
657 memset(buf, 0, buflen);
660 /* shift till we have 0x01 */
661 if ((v & 0x01) == 0) {
664 v >>= 4; off += 4; continue;
666 v >>= 3; off += 3; continue;
667 case 0x04: case 0x0c:
668 v >>= 2; off += 2; continue;
670 v >>= 1; off += 1; continue;
674 /* we have 0x01 with us */
675 for (i = 0; i < 32 - off; i++) {
676 if ((v & (0x01 << i)) == 0)
680 l = g_snprintf(p, ep - p, ",%d", s + off);
682 l = g_snprintf(p, ep - p, ",%d-%d", s + off,
685 if (l == -1 || l >= ep - p) {
695 bitrange(tvbuff_t *tvb, int offset, int l, int s)
697 static char buf[1024];
701 memset(buf, 0, sizeof(buf));
703 eq = buf + sizeof(buf) - 1;
704 for (i = 0; i < l; i++) {
705 if (bitrange0(tvb_get_ntohl(tvb, offset + i * 4), s + i * 4, q, eq - q) == NULL) {
706 if (q != buf && q + 5 < buf + sizeof(buf))
707 strncpy(q, ",...", 5);
716 dissect_nodeinfo(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
718 proto_tree *field_tree;
720 struct icmp6_nodeinfo icmp6_nodeinfo, *ni;
728 ni = &icmp6_nodeinfo;
729 tvb_memcpy(tvb, (guint8 *)ni, offset, sizeof *ni);
731 flags = pntohs(&ni->ni_flags);
732 tf = proto_tree_add_text(tree, tvb,
733 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
734 sizeof(ni->ni_flags), "Flags: 0x%04x", flags);
735 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_flag);
736 switch (pntohs(&ni->ni_qtype)) {
737 case NI_QTYPE_SUPTYPES:
738 if (ni->ni_type == ICMP6_NI_QUERY) {
739 proto_tree_add_text(field_tree, tvb,
740 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
741 sizeof(ni->ni_flags), "%s",
742 decode_boolean_bitfield(flags, NI_SUPTYPE_FLAG_COMPRESS, sizeof(flags) * 8,
743 "Compressed reply supported",
744 "No compressed reply support"));
746 proto_tree_add_text(field_tree, tvb,
747 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
748 sizeof(ni->ni_flags), "%s",
749 decode_boolean_bitfield(flags, NI_SUPTYPE_FLAG_COMPRESS, sizeof(flags) * 8,
750 "Compressed", "Not compressed"));
753 case NI_QTYPE_DNSNAME:
754 if (ni->ni_type == ICMP6_NI_REPLY) {
755 proto_tree_add_text(field_tree, tvb,
756 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
757 sizeof(ni->ni_flags), "%s",
758 decode_boolean_bitfield(flags, NI_FQDN_FLAG_VALIDTTL, sizeof(flags) * 8,
759 "Valid TTL field", "Meaningless TTL field"));
762 case NI_QTYPE_NODEADDR:
763 proto_tree_add_text(field_tree, tvb,
764 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
765 sizeof(ni->ni_flags), "%s",
766 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_GLOBAL, sizeof(flags) * 8,
768 "Not global address"));
769 proto_tree_add_text(field_tree, tvb,
770 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
771 sizeof(ni->ni_flags), "%s",
772 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_SITELOCAL, sizeof(flags) * 8,
773 "Site-local address",
774 "Not site-local address"));
775 proto_tree_add_text(field_tree, tvb,
776 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
777 sizeof(ni->ni_flags), "%s",
778 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_LINKLOCAL, sizeof(flags) * 8,
779 "Link-local address",
780 "Not link-local address"));
781 proto_tree_add_text(field_tree, tvb,
782 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
783 sizeof(ni->ni_flags), "%s",
784 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_COMPAT, sizeof(flags) * 8,
785 "IPv4 compatible/mapped address",
786 "Not IPv4 compatible/mapped address"));
788 case NI_QTYPE_IPV4ADDR:
789 proto_tree_add_text(field_tree, tvb,
790 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
791 sizeof(ni->ni_flags), "%s",
792 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_ALL, sizeof(flags) * 8,
793 "All unicast address",
794 "Unicast addresses on the queried interface"));
795 proto_tree_add_text(field_tree, tvb,
796 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
797 sizeof(ni->ni_flags), "%s",
798 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_TRUNCATE, sizeof(flags) * 8,
799 "Truncated", "Not truncated"));
804 proto_tree_add_text(tree, tvb,
805 offset + offsetof(struct icmp6_nodeinfo, icmp6_ni_nonce[0]),
806 sizeof(ni->icmp6_ni_nonce), "Nonce: 0x%08x%08x",
807 pntohl(&ni->icmp6_ni_nonce[0]), pntohl(&ni->icmp6_ni_nonce[4]));
809 /* offset for "the rest of data" */
813 if (!tvb_bytes_exist(tvb, offset, sizeof(*ni)))
815 if (ni->ni_type == ICMP6_NI_QUERY) {
816 switch (ni->ni_code) {
817 case ICMP6_NI_SUBJ_IPV6:
818 n = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
819 n /= sizeof(struct e_in6_addr);
820 tf = proto_tree_add_text(tree, tvb,
821 offset + sizeof(*ni), -1, "IPv6 subject addresses");
822 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_subject6);
823 p = offset + sizeof *ni;
824 for (i = 0; i < n; i++) {
825 struct e_in6_addr e_in6_addr;
826 tvb_get_ipv6(tvb, p, &e_in6_addr);
827 proto_tree_add_text(field_tree, tvb,
828 p, sizeof(struct e_in6_addr),
829 "%s", ip6_to_str(&e_in6_addr));
830 p += sizeof(struct e_in6_addr);
832 off = tvb_length_remaining(tvb, offset);
834 case ICMP6_NI_SUBJ_FQDN:
835 l = get_dns_name(tvb, offset + sizeof(*ni),
836 offset + sizeof(*ni), &dname);
837 if (tvb_bytes_exist(tvb, offset + sizeof(*ni) + l, 1) &&
838 tvb_get_guint8(tvb, offset + sizeof(*ni) + l) == 0) {
840 proto_tree_add_text(tree, tvb, offset + sizeof(*ni), l,
841 "DNS label: %s (truncated)", dname);
843 proto_tree_add_text(tree, tvb, offset + sizeof(*ni), l,
844 "DNS label: %s", dname);
846 off = tvb_length_remaining(tvb, offset + sizeof(*ni) + l);
848 case ICMP6_NI_SUBJ_IPV4:
849 n = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
850 n /= sizeof(guint32);
851 tf = proto_tree_add_text(tree, tvb,
852 offset + sizeof(*ni), -1, "IPv4 subject addresses");
853 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_subject4);
854 p = offset + sizeof *ni;
855 for (i = 0; i < n; i++) {
856 ipaddr = tvb_get_ipv4(tvb, p);
857 proto_tree_add_text(field_tree, tvb,
858 p, sizeof(guint32), "%s", ip_to_str((guint8 *)&ipaddr));
859 p += sizeof(guint32);
861 off = tvb_length_remaining(tvb, offset);
865 switch (pntohs(&ni->ni_qtype)) {
868 case NI_QTYPE_SUPTYPES:
869 p = offset + sizeof *ni;
870 tf = proto_tree_add_text(tree, tvb,
871 offset + sizeof(*ni), -1,
872 "Supported type bitmap%s",
873 (flags & 0x0001) ? ", compressed" : "");
874 field_tree = proto_item_add_subtree(tf,
875 ett_nodeinfo_nodebitmap);
877 while (tvb_bytes_exist(tvb, p, sizeof(guint32))) { /* XXXX Check what? */
878 if ((flags & 0x0001) == 0) {
879 l = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
880 l /= sizeof(guint32);
883 l = tvb_get_ntohs(tvb, p);
884 i = tvb_get_ntohs(tvb, p + sizeof(guint16)); /*skip*/
886 if (n + l * 32 > (1 << 16))
888 if (n + (l + i) * 32 > (1 << 16))
890 if ((flags & 0x0001) == 0) {
891 proto_tree_add_text(field_tree, tvb, p,
892 l * 4, "Bitmap (%d to %d): %s", n, n + l * 32 - 1,
893 bitrange(tvb, p, l, n));
896 proto_tree_add_text(field_tree, tvb, p,
897 4 + l * 4, "Bitmap (%d to %d): %s", n, n + l * 32 - 1,
898 bitrange(tvb, p + 4, l, n));
901 n += l * 32 + i * 32;
903 off = tvb_length_remaining(tvb, offset);
905 case NI_QTYPE_DNSNAME:
906 proto_tree_add_text(tree, tvb, offset + sizeof(*ni),
907 sizeof(gint32), "TTL: %d", (gint32)tvb_get_ntohl(tvb, offset + sizeof *ni));
908 tf = proto_tree_add_text(tree, tvb,
909 offset + sizeof(*ni) + sizeof(guint32), -1,
911 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_nodedns);
912 j = offset + sizeof (*ni) + sizeof(guint32);
913 while (j < tvb_reported_length(tvb)) {
914 l = get_dns_name(tvb, j,
915 offset + sizeof (*ni) + sizeof(guint32),
917 if (tvb_bytes_exist(tvb, j + l, 1) &&
918 tvb_get_guint8(tvb, j + l) == 0) {
920 proto_tree_add_text(field_tree, tvb, j, l,
921 "DNS label: %s (truncated)", dname);
923 proto_tree_add_text(field_tree, tvb, j, l,
924 "DNS label: %s", dname);
928 off = tvb_length_remaining(tvb, offset);
930 case NI_QTYPE_NODEADDR:
931 n = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
932 n /= sizeof(gint32) + sizeof(struct e_in6_addr);
933 tf = proto_tree_add_text(tree, tvb,
934 offset + sizeof(*ni), -1, "IPv6 node addresses");
935 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_node6);
936 p = offset + sizeof (*ni);
937 for (i = 0; i < n; i++) {
938 struct e_in6_addr e_in6_addr;
940 ttl = (gint32)tvb_get_ntohl(tvb, p);
941 tvb_get_ipv6(tvb, p + sizeof ttl, &e_in6_addr);
942 proto_tree_add_text(field_tree, tvb,
943 p, sizeof(struct e_in6_addr) + sizeof(gint32),
944 "%s (TTL %d)", ip6_to_str(&e_in6_addr), ttl);
945 p += sizeof(struct e_in6_addr) + sizeof(gint32);
947 off = tvb_length_remaining(tvb, offset);
949 case NI_QTYPE_IPV4ADDR:
950 n = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
951 n /= sizeof(gint32) + sizeof(guint32);
952 tf = proto_tree_add_text(tree, tvb,
953 offset + sizeof(*ni), -1, "IPv4 node addresses");
954 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_node4);
955 p = offset + sizeof *ni;
956 for (i = 0; i < n; i++) {
957 ipaddr = tvb_get_ipv4(tvb, sizeof(gint32) + p);
958 proto_tree_add_text(field_tree, tvb,
959 p, sizeof(guint32), "%s (TTL %d)",
960 ip_to_str((guint8 *)&ipaddr), tvb_get_ntohl(tvb, p));
961 p += sizeof(gint32) + sizeof(guint32);
963 off = tvb_length_remaining(tvb, offset);
969 /* the rest of data */
970 call_dissector(data_handle,tvb_new_subset(tvb, offset + off, -1, -1), pinfo, tree);
974 dissect_rrenum(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
976 proto_tree *field_tree, *opt_tree;
978 struct icmp6_router_renum icmp6_router_renum, *rr;
979 struct rr_pco_match rr_pco_match, *match;
980 struct rr_pco_use rr_pco_use, *use;
985 rr = &icmp6_router_renum;
986 tvb_memcpy(tvb, (guint8 *)rr, offset, sizeof *rr);
987 proto_tree_add_text(tree, tvb,
988 offset + offsetof(struct icmp6_router_renum, rr_seqnum), 4,
989 "Sequence number: 0x%08x", pntohl(&rr->rr_seqnum));
990 proto_tree_add_text(tree, tvb,
991 offset + offsetof(struct icmp6_router_renum, rr_segnum), 1,
992 "Segment number: 0x%02x", rr->rr_segnum);
994 flagoff = offset + offsetof(struct icmp6_router_renum, rr_flags);
995 flags = tvb_get_guint8(tvb, flagoff);
996 tf = proto_tree_add_text(tree, tvb, flagoff, 1,
997 "Flags: 0x%02x", flags);
998 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
999 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1000 decode_boolean_bitfield(flags, 0x80, 8,
1001 "Test command", "Not test command"));
1002 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1003 decode_boolean_bitfield(flags, 0x40, 8,
1004 "Result requested", "Result not requested"));
1005 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1006 decode_boolean_bitfield(flags, 0x20, 8,
1007 "All interfaces", "Not all interfaces"));
1008 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1009 decode_boolean_bitfield(flags, 0x10, 8,
1010 "Site specific", "Not site specific"));
1011 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1012 decode_boolean_bitfield(flags, 0x08, 8,
1013 "Processed previously", "Complete result"));
1015 proto_tree_add_text(tree, tvb,
1016 offset + offsetof(struct icmp6_router_renum, rr_maxdelay), 2,
1017 "Max delay: 0x%04x", pntohs(&rr->rr_maxdelay));
1018 call_dissector(data_handle,tvb_new_subset(tvb, offset + sizeof(*rr), -1, -1), pinfo, tree); /*XXX*/
1020 if (rr->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) {
1021 off = offset + sizeof(*rr);
1022 match = &rr_pco_match;
1023 tvb_memcpy(tvb, (guint8 *)match, off, sizeof *match);
1024 tf = proto_tree_add_text(tree, tvb, off, sizeof(*match),
1025 "Match-Prefix: %s/%u (%u-%u)", ip6_to_str(&match->rpm_prefix),
1026 match->rpm_matchlen, match->rpm_minlen, match->rpm_maxlen);
1027 opt_tree = proto_item_add_subtree(tf, ett_icmpv6opt);
1028 proto_tree_add_text(opt_tree, tvb,
1029 off + offsetof(struct rr_pco_match, rpm_code),
1030 sizeof(match->rpm_code), "OpCode: %s (%u)",
1031 val_to_str(match->rpm_code, names_rrenum_matchcode, "Unknown"),
1033 proto_tree_add_text(opt_tree, tvb,
1034 off + offsetof(struct rr_pco_match, rpm_len),
1035 sizeof(match->rpm_len), "OpLength: %u (%u octets)",
1036 match->rpm_len, match->rpm_len * 8);
1037 proto_tree_add_text(opt_tree, tvb,
1038 off + offsetof(struct rr_pco_match, rpm_ordinal),
1039 sizeof(match->rpm_ordinal), "Ordinal: %u", match->rpm_ordinal);
1040 proto_tree_add_text(opt_tree, tvb,
1041 off + offsetof(struct rr_pco_match, rpm_matchlen),
1042 sizeof(match->rpm_matchlen), "MatchLen: %u", match->rpm_matchlen);
1043 proto_tree_add_text(opt_tree, tvb,
1044 off + offsetof(struct rr_pco_match, rpm_minlen),
1045 sizeof(match->rpm_minlen), "MinLen: %u", match->rpm_minlen);
1046 proto_tree_add_text(opt_tree, tvb,
1047 off + offsetof(struct rr_pco_match, rpm_maxlen),
1048 sizeof(match->rpm_maxlen), "MaxLen: %u", match->rpm_maxlen);
1049 proto_tree_add_text(opt_tree, tvb,
1050 off + offsetof(struct rr_pco_match, rpm_prefix),
1051 sizeof(match->rpm_prefix), "MatchPrefix: %s",
1052 ip6_to_str(&match->rpm_prefix));
1054 off += sizeof(*match);
1056 for (l = match->rpm_len * 8 - sizeof(*match);
1057 l >= sizeof(*use); l -= sizeof(*use), off += sizeof(*use)) {
1058 tvb_memcpy(tvb, (guint8 *)use, off, sizeof *use);
1059 tf = proto_tree_add_text(tree, tvb, off, sizeof(*use),
1060 "Use-Prefix: %s/%u (keep %u)", ip6_to_str(&use->rpu_prefix),
1061 use->rpu_uselen, use->rpu_keeplen);
1062 opt_tree = proto_item_add_subtree(tf, ett_icmpv6opt);
1063 proto_tree_add_text(opt_tree, tvb,
1064 off + offsetof(struct rr_pco_use, rpu_uselen),
1065 sizeof(use->rpu_uselen), "UseLen: %u", use->rpu_uselen);
1066 proto_tree_add_text(opt_tree, tvb,
1067 off + offsetof(struct rr_pco_use, rpu_keeplen),
1068 sizeof(use->rpu_keeplen), "KeepLen: %u", use->rpu_keeplen);
1069 tf = proto_tree_add_text(opt_tree, tvb,
1070 flagoff = off + offsetof(struct rr_pco_use, rpu_ramask),
1071 sizeof(use->rpu_ramask), "FlagMask: 0x%x", use->rpu_ramask);
1072 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1073 flags = tvb_get_guint8(tvb, flagoff);
1074 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1075 decode_boolean_bitfield(flags,
1076 ICMP6_RR_PCOUSE_RAFLAGS_ONLINK, 8,
1077 "Onlink", "Not onlink"));
1078 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1079 decode_boolean_bitfield(flags,
1080 ICMP6_RR_PCOUSE_RAFLAGS_AUTO, 8,
1081 "Auto", "Not auto"));
1082 tf = proto_tree_add_text(opt_tree, tvb,
1083 flagoff = off + offsetof(struct rr_pco_use, rpu_raflags),
1084 sizeof(use->rpu_raflags), "RAFlags: 0x%x", use->rpu_raflags);
1085 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1086 flags = tvb_get_guint8(tvb, flagoff);
1087 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1088 decode_boolean_bitfield(flags,
1089 ICMP6_RR_PCOUSE_RAFLAGS_ONLINK, 8,
1090 "Onlink", "Not onlink"));
1091 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1092 decode_boolean_bitfield(flags,
1093 ICMP6_RR_PCOUSE_RAFLAGS_AUTO, 8, "Auto", "Not auto"));
1094 if (pntohl(&use->rpu_vltime) == 0xffffffff)
1095 proto_tree_add_text(opt_tree, tvb,
1096 off + offsetof(struct rr_pco_use, rpu_vltime),
1097 sizeof(use->rpu_vltime), "Valid Lifetime: infinity");
1099 proto_tree_add_text(opt_tree, tvb,
1100 off + offsetof(struct rr_pco_use, rpu_vltime),
1101 sizeof(use->rpu_vltime), "Valid Lifetime: %u",
1102 pntohl(&use->rpu_vltime));
1103 if (pntohl(&use->rpu_pltime) == 0xffffffff)
1104 proto_tree_add_text(opt_tree, tvb,
1105 off + offsetof(struct rr_pco_use, rpu_pltime),
1106 sizeof(use->rpu_pltime), "Preferred Lifetime: infinity");
1108 proto_tree_add_text(opt_tree, tvb,
1109 off + offsetof(struct rr_pco_use, rpu_pltime),
1110 sizeof(use->rpu_pltime), "Preferred Lifetime: %u",
1111 pntohl(&use->rpu_pltime));
1112 tf = proto_tree_add_text(opt_tree, tvb,
1113 flagoff = off + offsetof(struct rr_pco_use, rpu_flags),
1114 sizeof(use->rpu_flags), "Flags: 0x%08x",
1115 pntohl(&use->rpu_flags));
1116 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1117 flags = tvb_get_guint8(tvb, flagoff);
1118 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
1119 decode_boolean_bitfield(flags,
1120 ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, 32,
1121 "Decrement valid lifetime", "No decrement valid lifetime"));
1122 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
1123 decode_boolean_bitfield(flags,
1124 ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, 32,
1125 "Decrement preferred lifetime",
1126 "No decrement preferred lifetime"));
1127 proto_tree_add_text(opt_tree, tvb,
1128 off + offsetof(struct rr_pco_use, rpu_prefix),
1129 sizeof(use->rpu_prefix), "UsePrefix: %s",
1130 ip6_to_str(&use->rpu_prefix));
1137 * See I-D draft-vida-mld-v2-08
1139 static const value_string mldrv2ModesNames[] = {
1142 { 3, "Changed to include" },
1143 { 4, "Changed to exclude" },
1144 { 5, "Allow new sources" },
1145 { 6, "Block old sources" },
1150 dissect_mldrv2( tvbuff_t *tvb, guint32 offset, guint16 count, proto_tree *tree )
1152 proto_tree *sub_tree;
1155 guint8 recordType, auxDataLen;
1156 guint32 sourceNb, recordSize, localOffset;
1157 struct e_in6_addr addr;
1159 for( ; count; count--, offset += recordSize ) {
1160 localOffset = offset;
1161 recordType = tvb_get_guint8( tvb, localOffset );
1163 auxDataLen = tvb_get_guint8( tvb, localOffset );
1165 sourceNb = tvb_get_ntohs( tvb, localOffset );
1167 recordSize = 4 + 16 + (16 * sourceNb) + (auxDataLen * 4);
1169 tvb_get_ipv6(tvb, localOffset, &addr);
1170 tf = proto_tree_add_text( tree, tvb, offset, recordSize,
1172 "%s: %s (%s)", val_to_str(recordType, mldrv2ModesNames,"Unknown mode"),
1173 get_hostname6(&addr), ip6_to_str(&addr)
1175 "%s: %s", val_to_str(recordType, mldrv2ModesNames,"Unknown mode"),
1179 sub_tree = proto_item_add_subtree(tf, ett_multicastRR);
1181 proto_tree_add_text( sub_tree, tvb, offset, 1, "Mode: %s",
1182 val_to_str(recordType, mldrv2ModesNames,"Unknown mode") );
1183 proto_tree_add_text( sub_tree, tvb, offset+1, 1, "Aux data len: %u", auxDataLen * 4);
1184 proto_tree_add_text( sub_tree, tvb, localOffset, 16, "Multicast Address: %s", ip6_to_str(&addr) );
1187 for( ; sourceNb; sourceNb--, localOffset += 16 ) {
1188 tvb_get_ipv6(tvb, localOffset, &addr);
1189 proto_tree_add_text( sub_tree, tvb, localOffset, 16,
1191 "Source Address: %s (%s)", get_hostname6(&addr), ip6_to_str(&addr) );
1193 "Source Address: %s", ip6_to_str(&addr) );
1200 dissect_mldqv2(tvbuff_t *tvb, guint32 offset, guint16 count, proto_tree *tree)
1202 struct e_in6_addr addr;
1204 for ( ; count; count--, offset += 16) {
1205 tvb_get_ipv6(tvb, offset, &addr);
1206 proto_tree_add_text(tree, tvb, offset, 16,
1207 "Source Address: %s (%s)", get_hostname6(&addr), ip6_to_str(&addr));
1212 dissect_icmpv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1214 proto_tree *icmp6_tree, *field_tree;
1215 proto_item *ti, *tf = NULL;
1216 struct icmp6_hdr icmp6_hdr, *dp;
1217 struct icmp6_nodeinfo *ni = NULL;
1218 const char *codename, *typename;
1219 const char *colcodename, *coltypename;
1221 guint length, reported_length;
1224 guint16 cksum, computed_cksum;
1228 if (check_col(pinfo->cinfo, COL_PROTOCOL))
1229 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ICMPv6");
1230 if (check_col(pinfo->cinfo, COL_INFO))
1231 col_clear(pinfo->cinfo, COL_INFO);
1234 tvb_memcpy(tvb, (guint8 *)&icmp6_hdr, offset, sizeof icmp6_hdr);
1236 codename = typename = colcodename = coltypename = "Unknown";
1238 switch (dp->icmp6_type) {
1239 case ICMP6_DST_UNREACH:
1240 typename = coltypename = "Unreachable";
1241 switch (dp->icmp6_code) {
1242 case ICMP6_DST_UNREACH_NOROUTE:
1243 codename = colcodename = "Route unreachable";
1245 case ICMP6_DST_UNREACH_ADMIN:
1246 codename = colcodename = "Administratively prohibited";
1248 case ICMP6_DST_UNREACH_NOTNEIGHBOR:
1249 codename = colcodename = "Not a neighbor";
1251 case ICMP6_DST_UNREACH_ADDR:
1252 codename = colcodename = "Address unreachable";
1254 case ICMP6_DST_UNREACH_NOPORT:
1255 codename = colcodename = "Port unreachable";
1259 case ICMP6_PACKET_TOO_BIG:
1260 typename = coltypename = "Too big";
1261 codename = colcodename = NULL;
1263 case ICMP6_TIME_EXCEEDED:
1264 typename = coltypename = "Time exceeded";
1265 switch (dp->icmp6_code) {
1266 case ICMP6_TIME_EXCEED_TRANSIT:
1267 codename = colcodename = "In-transit";
1269 case ICMP6_TIME_EXCEED_REASSEMBLY:
1270 codename = colcodename = "Reassembly";
1274 case ICMP6_PARAM_PROB:
1275 typename = coltypename = "Parameter problem";
1276 switch (dp->icmp6_code) {
1277 case ICMP6_PARAMPROB_HEADER:
1278 codename = colcodename = "Header";
1280 case ICMP6_PARAMPROB_NEXTHEADER:
1281 codename = colcodename = "Next header";
1283 case ICMP6_PARAMPROB_OPTION:
1284 codename = colcodename = "Option";
1288 case ICMP6_ECHO_REQUEST:
1289 typename = coltypename = "Echo request";
1290 codename = colcodename = NULL;
1292 case ICMP6_ECHO_REPLY:
1293 typename = coltypename = "Echo reply";
1294 codename = colcodename = NULL;
1296 case ICMP6_MEMBERSHIP_QUERY:
1297 typename = coltypename = "Multicast listener query";
1298 codename = colcodename = NULL;
1300 case ICMP6_MEMBERSHIP_REPORT:
1301 typename = coltypename = "Multicast listener report";
1302 codename = colcodename = NULL;
1304 case ICMP6_MEMBERSHIP_REDUCTION:
1305 typename = coltypename = "Multicast listener done";
1306 codename = colcodename = NULL;
1308 case ND_ROUTER_SOLICIT:
1309 typename = coltypename = "Router solicitation";
1310 codename = colcodename = NULL;
1311 len = sizeof(struct nd_router_solicit);
1313 case ND_ROUTER_ADVERT:
1314 typename = coltypename = "Router advertisement";
1315 codename = colcodename = NULL;
1316 len = sizeof(struct nd_router_advert);
1318 case ND_NEIGHBOR_SOLICIT:
1319 typename = coltypename = "Neighbor solicitation";
1320 codename = colcodename = NULL;
1321 len = sizeof(struct nd_neighbor_solicit);
1323 case ND_NEIGHBOR_ADVERT:
1324 typename = coltypename = "Neighbor advertisement";
1325 codename = colcodename = NULL;
1326 len = sizeof(struct nd_neighbor_advert);
1329 typename = coltypename = "Redirect";
1330 codename = colcodename = NULL;
1331 len = sizeof(struct nd_redirect);
1333 case ICMP6_ROUTER_RENUMBERING:
1334 typename = coltypename = "Router renumbering";
1335 switch (dp->icmp6_code) {
1336 case ICMP6_ROUTER_RENUMBERING_COMMAND:
1337 codename = colcodename = "Command";
1339 case ICMP6_ROUTER_RENUMBERING_RESULT:
1340 codename = colcodename = "Result";
1342 case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
1343 codename = colcodename = "Sequence number reset";
1346 len = sizeof(struct icmp6_router_renum);
1348 case ICMP6_NI_QUERY:
1349 case ICMP6_NI_REPLY:
1350 ni = (struct icmp6_nodeinfo *)dp;
1351 if (ni->ni_type == ICMP6_NI_QUERY) {
1352 typename = coltypename = "Node information query";
1353 switch (ni->ni_code) {
1354 case ICMP6_NI_SUBJ_IPV6:
1355 codename = "Query subject = IPv6 addresses";
1357 case ICMP6_NI_SUBJ_FQDN:
1358 if (tvb_bytes_exist(tvb, offset, sizeof(*ni)))
1359 codename = "Query subject = DNS name";
1361 codename = "Query subject = empty";
1363 case ICMP6_NI_SUBJ_IPV4:
1364 codename = "Query subject = IPv4 addresses";
1368 typename = coltypename = "Node information reply";
1369 switch (ni->ni_code) {
1370 case ICMP6_NI_SUCCESS:
1371 codename = "Successful";
1373 case ICMP6_NI_REFUSED:
1374 codename = "Refused";
1376 case ICMP6_NI_UNKNOWN:
1377 codename = "Unknown query type";
1381 colcodename = val_to_str(pntohs(&ni->ni_qtype), names_nodeinfo_qtype,
1383 len = sizeof(struct icmp6_nodeinfo);
1385 case ICMP6_MIP6_DHAAD_REQUEST:
1386 typename = coltypename = "Dynamic Home Agent Address Discovery Request";
1387 codename = "Should always be zero";
1390 case ICMP6_MIP6_DHAAD_REPLY:
1391 typename = coltypename = "Dynamic Home Agent Address Discovery Reply";
1392 codename = "Should always be zero";
1395 case ICMP6_MIP6_MPS:
1396 typename = coltypename = "Mobile Prefix Solicitation";
1397 codename = "Should always be zero";
1400 case ICMP6_MIP6_MPA:
1401 typename = coltypename = "Mobile Prefix Advertisement";
1402 codename = "Should always be zero";
1405 case ICMP6_MLDV2_REPORT:
1406 typename = coltypename = "Multicast Listener Report Message v2";
1407 codename = "Should always be zero";
1410 case ICMP6_EXPERIMENTAL_MOBILITY:
1411 typename = coltypename ="Experimental Mobility";
1412 switch (dp->icmp6_data8[0]) {
1413 case FMIP6_SUBTYPE_RTSOLPR:
1414 typename = coltypename ="RtSolPr (ICMPv6 Experimental Mobility)";
1415 codename = "Should always be zero";
1418 case FMIP6_SUBTYPE_PRRTADV:
1419 typename = coltypename ="PrRtAdv (ICMPv6 Experimental Mobility)";
1420 codename = val_to_str(dp->icmp6_code, names_fmip6_prrtadv_code, "Unknown");
1423 case FMIP6_SUBTYPE_HI:
1424 typename = coltypename ="HI (ICMPv6 Experimental Mobility)";
1425 codename = val_to_str(dp->icmp6_code, names_fmip6_hi_code, "Unknown");
1428 case FMIP6_SUBTYPE_HACK:
1429 typename = coltypename ="HAck (ICMPv6 Experimental Mobility)";
1430 codename = val_to_str(dp->icmp6_code, names_fmip6_hack_code, "Unknown");
1437 if (check_col(pinfo->cinfo, COL_INFO)) {
1438 char typebuf[256], codebuf[256];
1440 if (coltypename && strcmp(coltypename, "Unknown") == 0) {
1441 g_snprintf(typebuf, sizeof(typebuf), "Unknown (0x%02x)",
1443 coltypename = typebuf;
1445 if (colcodename && strcmp(colcodename, "Unknown") == 0) {
1446 g_snprintf(codebuf, sizeof(codebuf), "Unknown (0x%02x)",
1448 colcodename = codebuf;
1451 col_add_fstr(pinfo->cinfo, COL_INFO, "%s (%s)", coltypename, colcodename);
1453 col_add_fstr(pinfo->cinfo, COL_INFO, "%s", coltypename);
1458 /* !!! specify length */
1459 ti = proto_tree_add_item(tree, proto_icmpv6, tvb, offset, -1, FALSE);
1460 icmp6_tree = proto_item_add_subtree(ti, ett_icmpv6);
1462 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_type, tvb,
1463 offset + offsetof(struct icmp6_hdr, icmp6_type), 1,
1465 "Type: %u (%s)", dp->icmp6_type, typename);
1467 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_code, tvb,
1468 offset + offsetof(struct icmp6_hdr, icmp6_code), 1,
1470 "Code: %u (%s)", dp->icmp6_code, codename);
1472 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_code, tvb,
1473 offset + offsetof(struct icmp6_hdr, icmp6_code), 1,
1475 "Code: %u", dp->icmp6_code);
1477 cksum = (guint16)g_htons(dp->icmp6_cksum);
1478 length = tvb_length(tvb);
1479 reported_length = tvb_reported_length(tvb);
1480 if (!pinfo->fragmented && length >= reported_length) {
1481 /* The packet isn't part of a fragmented datagram and isn't
1482 truncated, so we can checksum it. */
1484 /* Set up the fields of the pseudo-header. */
1485 cksum_vec[0].ptr = pinfo->src.data;
1486 cksum_vec[0].len = pinfo->src.len;
1487 cksum_vec[1].ptr = pinfo->dst.data;
1488 cksum_vec[1].len = pinfo->dst.len;
1489 cksum_vec[2].ptr = (const guint8 *)&phdr;
1490 phdr[0] = g_htonl(tvb_reported_length(tvb));
1491 phdr[1] = g_htonl(IP_PROTO_ICMPV6);
1492 cksum_vec[2].len = 8;
1493 cksum_vec[3].len = tvb_reported_length(tvb);
1494 cksum_vec[3].ptr = tvb_get_ptr(tvb, offset, cksum_vec[3].len);
1495 computed_cksum = in_cksum(cksum_vec, 4);
1496 if (computed_cksum == 0) {
1497 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_checksum,
1499 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1501 "Checksum: 0x%04x [correct]", cksum);
1503 proto_tree_add_boolean_hidden(icmp6_tree, hf_icmpv6_checksum_bad,
1505 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1507 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_checksum,
1509 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1511 "Checksum: 0x%04x [incorrect, should be 0x%04x]",
1512 cksum, in_cksum_shouldbe(cksum, computed_cksum));
1515 proto_tree_add_uint(icmp6_tree, hf_icmpv6_checksum, tvb,
1516 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1521 switch (dp->icmp6_type) {
1522 case ICMP6_DST_UNREACH:
1523 case ICMP6_TIME_EXCEEDED:
1524 dissect_contained_icmpv6(tvb, offset + sizeof(*dp), pinfo,
1527 case ICMP6_PACKET_TOO_BIG:
1528 proto_tree_add_text(icmp6_tree, tvb,
1529 offset + offsetof(struct icmp6_hdr, icmp6_mtu), 4,
1530 "MTU: %u", pntohl(&dp->icmp6_mtu));
1531 dissect_contained_icmpv6(tvb, offset + sizeof(*dp), pinfo,
1534 case ICMP6_PARAM_PROB:
1535 proto_tree_add_text(icmp6_tree, tvb,
1536 offset + offsetof(struct icmp6_hdr, icmp6_pptr), 4,
1537 "Problem pointer: 0x%04x", pntohl(&dp->icmp6_pptr));
1538 dissect_contained_icmpv6(tvb, offset + sizeof(*dp), pinfo,
1541 case ICMP6_ECHO_REQUEST:
1542 case ICMP6_ECHO_REPLY:
1543 proto_tree_add_text(icmp6_tree, tvb,
1544 offset + offsetof(struct icmp6_hdr, icmp6_id), 2,
1545 "ID: 0x%04x", (guint16)g_ntohs(dp->icmp6_id));
1546 proto_tree_add_text(icmp6_tree, tvb,
1547 offset + offsetof(struct icmp6_hdr, icmp6_seq), 2,
1548 "Sequence: 0x%04x", (guint16)g_ntohs(dp->icmp6_seq));
1549 next_tvb = tvb_new_subset(tvb, offset + sizeof(*dp), -1, -1);
1550 call_dissector(data_handle,next_tvb, pinfo, icmp6_tree);
1552 case ICMP6_MEMBERSHIP_QUERY:
1553 case ICMP6_MEMBERSHIP_REPORT:
1554 case ICMP6_MEMBERSHIP_REDUCTION:
1555 #define MLDV2_MINLEN 28
1556 #define MLDV1_MINLEN 24
1557 if (dp->icmp6_type == ICMP6_MEMBERSHIP_QUERY) {
1558 if (length >= MLDV2_MINLEN) {
1564 mrc = g_ntohs(dp->icmp6_maxdelay);
1565 flag = tvb_get_guint8(tvb, offset + sizeof(*dp) + 16);
1566 qqi = tvb_get_guint8(tvb, offset + sizeof(*dp) + 16 + 1);
1567 nsrcs = tvb_get_ntohs(tvb, offset + sizeof(*dp) + 16 + 2);
1570 mrc = ((mrc & 0x0fff) | 0x1000) <<
1571 (((mrc & 0x7000) >> 12) + 3);
1572 proto_tree_add_text(icmp6_tree, tvb,
1573 offset + offsetof(struct icmp6_hdr, icmp6_maxdelay), 2,
1574 "Maximum response delay[ms]: %u", mrc);
1576 proto_tree_add_text(icmp6_tree, tvb, offset + sizeof(*dp),
1577 16, "Multicast Address: %s",
1578 ip6_to_str((const struct e_in6_addr *)(tvb_get_ptr(tvb,
1579 offset + sizeof *dp, sizeof (struct e_in6_addr)))));
1581 proto_tree_add_text(icmp6_tree, tvb,
1582 offset + sizeof(*dp) + 16, 1, "S Flag: %s",
1583 flag & 0x08 ? "ON" : "OFF");
1584 proto_tree_add_text(icmp6_tree, tvb,
1585 offset + sizeof(*dp) + 16, 1, "Robustness: %d",
1588 qqi = ((qqi & 0x0f) | 0x10) << (((qqi & 0x70) >> 4) + 3);
1589 proto_tree_add_text(icmp6_tree, tvb,
1590 offset + sizeof(*dp) + 17, 1, "QQI: %d", qqi);
1592 dissect_mldqv2(tvb, offset + sizeof(*dp) + 20, nsrcs,
1595 } else if (length > MLDV1_MINLEN) {
1596 next_tvb = tvb_new_subset(tvb, offset + sizeof(*dp), -1, -1);
1597 call_dissector(data_handle,next_tvb, pinfo, tree);
1600 /* MLDv1 Query -> FALLTHOUGH */
1604 proto_tree_add_text(icmp6_tree, tvb,
1605 offset + offsetof(struct icmp6_hdr, icmp6_maxdelay), 2,
1606 "Maximum response delay: %u",
1607 (guint16)g_ntohs(dp->icmp6_maxdelay));
1608 proto_tree_add_text(icmp6_tree, tvb, offset + sizeof(*dp), 16,
1609 "Multicast Address: %s",
1610 ip6_to_str((const struct e_in6_addr *)(tvb_get_ptr(tvb, offset + sizeof *dp, sizeof (struct e_in6_addr)))));
1612 case ND_ROUTER_SOLICIT:
1613 dissect_icmpv6ndopt(tvb, offset + sizeof(*dp), pinfo, icmp6_tree);
1615 case ICMP6_MLDV2_REPORT: {
1618 nbRecords = tvb_get_ntohs( tvb, offset+4+2 );
1619 dissect_mldrv2( tvb, offset+4+2+2, nbRecords, icmp6_tree );
1622 case ND_ROUTER_ADVERT:
1624 struct nd_router_advert nd_router_advert, *ra;
1628 ra = &nd_router_advert;
1629 tvb_memcpy(tvb, (guint8 *)ra, offset, sizeof *ra);
1630 proto_tree_add_text(icmp6_tree, tvb,
1631 offset + offsetof(struct nd_router_advert, nd_ra_curhoplimit),
1632 1, "Cur hop limit: %u", ra->nd_ra_curhoplimit);
1634 flagoff = offset + offsetof(struct nd_router_advert, nd_ra_flags_reserved);
1635 ra_flags = tvb_get_guint8(tvb, flagoff);
1636 tf = proto_tree_add_text(icmp6_tree, tvb, flagoff, 1, "Flags: 0x%02x", ra_flags);
1637 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1638 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1639 decode_boolean_bitfield(ra_flags,
1640 ND_RA_FLAG_MANAGED, 8, "Managed", "Not managed"));
1641 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1642 decode_boolean_bitfield(ra_flags,
1643 ND_RA_FLAG_OTHER, 8, "Other", "Not other"));
1644 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1645 decode_boolean_bitfield(ra_flags,
1646 ND_RA_FLAG_HOME_AGENT, 8,
1647 "Home Agent", "Not Home Agent"));
1648 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1649 decode_enumerated_bitfield(ra_flags, ND_RA_FLAG_RTPREF_MASK, 8,
1650 names_router_pref, "Router preference: %s"));
1651 proto_tree_add_text(icmp6_tree, tvb,
1652 offset + offsetof(struct nd_router_advert, nd_ra_router_lifetime),
1653 2, "Router lifetime: %u",
1654 (guint16)g_ntohs(ra->nd_ra_router_lifetime));
1655 proto_tree_add_text(icmp6_tree, tvb,
1656 offset + offsetof(struct nd_router_advert, nd_ra_reachable), 4,
1657 "Reachable time: %u", pntohl(&ra->nd_ra_reachable));
1658 proto_tree_add_text(icmp6_tree, tvb,
1659 offset + offsetof(struct nd_router_advert, nd_ra_retransmit), 4,
1660 "Retrans time: %u", pntohl(&ra->nd_ra_retransmit));
1661 dissect_icmpv6ndopt(tvb, offset + sizeof(struct nd_router_advert), pinfo, icmp6_tree);
1664 case ND_NEIGHBOR_SOLICIT:
1666 struct nd_neighbor_solicit nd_neighbor_solicit, *ns;
1668 ns = &nd_neighbor_solicit;
1669 tvb_memcpy(tvb, (guint8 *)ns, offset, sizeof *ns);
1670 proto_tree_add_text(icmp6_tree, tvb,
1671 offset + offsetof(struct nd_neighbor_solicit, nd_ns_target), 16,
1674 get_hostname6(&ns->nd_ns_target),
1678 ip6_to_str(&ns->nd_ns_target));
1680 dissect_icmpv6ndopt(tvb, offset + sizeof(*ns), pinfo, icmp6_tree);
1683 case ND_NEIGHBOR_ADVERT:
1685 int flagoff, targetoff;
1687 struct e_in6_addr na_target;
1689 flagoff = offset + offsetof(struct nd_neighbor_advert, nd_na_flags_reserved);
1690 na_flags = tvb_get_ntohl(tvb, flagoff);
1692 tf = proto_tree_add_text(icmp6_tree, tvb, flagoff, 4, "Flags: 0x%08x", na_flags);
1693 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1694 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
1695 decode_boolean_bitfield(na_flags,
1696 ND_NA_FLAG_ROUTER, 32, "Router", "Not router"));
1697 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
1698 decode_boolean_bitfield(na_flags,
1699 ND_NA_FLAG_SOLICITED, 32, "Solicited", "Not adverted"));
1700 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
1701 decode_boolean_bitfield(na_flags,
1702 ND_NA_FLAG_OVERRIDE, 32, "Override", "Not override"));
1704 targetoff = offset + offsetof(struct nd_neighbor_advert, nd_na_target);
1705 tvb_memcpy(tvb, (guint8 *)&na_target, targetoff, sizeof na_target);
1706 proto_tree_add_text(icmp6_tree, tvb, targetoff, 16,
1709 get_hostname6(&na_target),
1713 ip6_to_str(&na_target));
1715 dissect_icmpv6ndopt(tvb, offset + sizeof(struct nd_neighbor_advert), pinfo, icmp6_tree);
1720 struct nd_redirect nd_redirect, *rd;
1723 tvb_memcpy(tvb, (guint8 *)rd, offset, sizeof *rd);
1724 proto_tree_add_text(icmp6_tree, tvb,
1725 offset + offsetof(struct nd_redirect, nd_rd_target), 16,
1728 get_hostname6(&rd->nd_rd_target),
1732 ip6_to_str(&rd->nd_rd_target));
1734 proto_tree_add_text(icmp6_tree, tvb,
1735 offset + offsetof(struct nd_redirect, nd_rd_dst), 16,
1737 "Destination: %s (%s)",
1738 get_hostname6(&rd->nd_rd_dst),
1742 ip6_to_str(&rd->nd_rd_dst));
1744 dissect_icmpv6ndopt(tvb, offset + sizeof(*rd), pinfo, icmp6_tree);
1747 case ICMP6_ROUTER_RENUMBERING:
1748 dissect_rrenum(tvb, offset, pinfo, icmp6_tree);
1750 case ICMP6_NI_QUERY:
1751 case ICMP6_NI_REPLY:
1752 ni = (struct icmp6_nodeinfo *)dp;
1753 proto_tree_add_text(icmp6_tree, tvb,
1754 offset + offsetof(struct icmp6_nodeinfo, ni_qtype),
1755 sizeof(ni->ni_qtype),
1756 "Query type: 0x%04x (%s)", pntohs(&ni->ni_qtype),
1757 val_to_str(pntohs(&ni->ni_qtype), names_nodeinfo_qtype,
1759 dissect_nodeinfo(tvb, offset, pinfo, icmp6_tree);
1761 case ICMP6_MIP6_DHAAD_REQUEST:
1762 proto_tree_add_text(icmp6_tree, tvb,
1763 offset + 4, 2, "Identifier: %d (0x%02x)",
1764 tvb_get_ntohs(tvb, offset + 4),
1765 tvb_get_ntohs(tvb, offset + 4));
1766 proto_tree_add_text(icmp6_tree, tvb,
1767 offset + 6, 2, "Reserved: %d",
1768 tvb_get_ntohs(tvb, offset + 6));
1770 case ICMP6_MIP6_DHAAD_REPLY:
1771 proto_tree_add_text(icmp6_tree, tvb,
1772 offset + 4, 2, "Identifier: %d (0x%02x)",
1773 tvb_get_ntohs(tvb, offset + 4),
1774 tvb_get_ntohs(tvb, offset + 4));
1775 proto_tree_add_text(icmp6_tree, tvb,
1776 offset + 6, 2, "Reserved: %d",
1777 tvb_get_ntohs(tvb, offset + 6));
1778 /* Show all Home Agent Addresses */
1781 int ha_num = (length - 8)/16;
1783 for (i = 0; i < ha_num; i++) {
1785 proto_tree_add_ipv6(icmp6_tree, hf_icmpv6_haad_ha_addrs,
1786 tvb, offset + 8 + suboffset, 16,
1787 tvb_get_ptr(tvb, offset + 8 + suboffset, 16));
1791 case ICMP6_MIP6_MPS:
1792 proto_tree_add_text(icmp6_tree, tvb,
1793 offset + 4, 2, "Identifier: %d (0x%02x)",
1794 tvb_get_ntohs(tvb, offset + 4),
1795 tvb_get_ntohs(tvb, offset + 4));
1796 proto_tree_add_text(icmp6_tree, tvb,
1797 offset + 6, 2, "Reserved: %d",
1798 tvb_get_ntohs(tvb, offset + 6));
1800 case ICMP6_MIP6_MPA:
1801 proto_tree_add_text(icmp6_tree, tvb,
1802 offset + 4, 2, "Identifier: %d (0x%02x)",
1803 tvb_get_ntohs(tvb, offset + 4),
1804 tvb_get_ntohs(tvb, offset + 4));
1805 proto_tree_add_text(icmp6_tree, tvb,
1807 decode_boolean_bitfield(tvb_get_guint8(tvb, offset + 6),
1809 "Managed Address Configuration",
1810 "No Managed Address Configuration"));
1811 proto_tree_add_text(icmp6_tree, tvb,
1813 decode_boolean_bitfield(tvb_get_guint8(tvb, offset + 6),
1815 "Other Stateful Configuration",
1816 "No Other Stateful Configuration"));
1817 proto_tree_add_text(icmp6_tree, tvb,
1818 offset + 7, 1, "Reserved: %d",
1819 tvb_get_guint8(tvb, offset + 7));
1820 /* Show all options */
1821 dissect_icmpv6ndopt(tvb, offset + 8, pinfo, icmp6_tree);
1823 case ICMP6_EXPERIMENTAL_MOBILITY:
1824 switch (dp->icmp6_data8[0]) {
1825 case FMIP6_SUBTYPE_RTSOLPR:
1827 struct fmip6_rtsolpr *rtsolpr;
1828 rtsolpr = (struct fmip6_rtsolpr*) dp;
1829 proto_tree_add_text(icmp6_tree, tvb,
1831 "Subtype: Router Solicitation for Proxy Advertisement");
1832 proto_tree_add_text(icmp6_tree, tvb,
1834 "Identifier: %d", pntohs(&rtsolpr->fmip6_rtsolpr_id));
1835 dissect_icmpv6fmip6opt(tvb, offset + sizeof(*dp), icmp6_tree);
1838 case FMIP6_SUBTYPE_PRRTADV:
1840 struct fmip6_prrtadv *prrtadv;
1841 prrtadv = (struct fmip6_prrtadv*) dp;
1842 proto_tree_add_text(icmp6_tree, tvb,
1844 "Subtype: Proxy Router Advertisement");
1845 proto_tree_add_text(icmp6_tree, tvb,
1847 "Identifier: %d", pntohs(&prrtadv->fmip6_prrtadv_id));
1848 dissect_icmpv6fmip6opt(tvb, offset + sizeof(*dp), icmp6_tree);
1851 case FMIP6_SUBTYPE_HI:
1853 struct fmip6_hi *hi;
1856 hi = (struct fmip6_hi*) dp;
1857 proto_tree_add_text(icmp6_tree, tvb,
1859 "Subtype: Handover Initiate");
1861 flagoff = offset + offsetof(struct fmip6_hi, fmip6_hi_flags_reserved);
1862 hi_flags = tvb_get_guint8(tvb, flagoff);
1863 tf = proto_tree_add_text(icmp6_tree, tvb, flagoff, 1, "Flags: 0x%02x", hi_flags);
1864 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1865 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1866 decode_boolean_bitfield(hi_flags,
1867 FMIP_HI_FLAG_ASSIGNED, 8, "Assigned", "Not assigned"));
1868 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1869 decode_boolean_bitfield(hi_flags,
1870 FMIP_HI_FLAG_BUFFER, 8, "Buffered", "Not buffered"));
1871 proto_tree_add_text(icmp6_tree, tvb,
1873 "Identifier: %d", pntohs(&hi->fmip6_hi_id));
1874 dissect_icmpv6fmip6opt(tvb, offset + sizeof(*dp), icmp6_tree);
1877 case FMIP6_SUBTYPE_HACK:
1879 struct fmip6_hack *hack;
1880 hack = (struct fmip6_hack*) dp;
1881 proto_tree_add_text(icmp6_tree, tvb,
1883 "Subtype: Handover Acknowledge");
1884 proto_tree_add_text(icmp6_tree, tvb,
1886 "Identifier: %d", pntohs(&hack->fmip6_hack_id));
1887 dissect_icmpv6fmip6opt(tvb, offset + sizeof(*dp), icmp6_tree);
1893 next_tvb = tvb_new_subset(tvb, offset + sizeof(*dp), -1, -1);
1894 call_dissector(data_handle,next_tvb, pinfo, tree);
1901 proto_register_icmpv6(void)
1903 static hf_register_info hf[] = {
1905 { "Type", "icmpv6.type", FT_UINT8, BASE_DEC, NULL, 0x0,
1908 { "Code", "icmpv6.code", FT_UINT8, BASE_DEC, NULL, 0x0,
1910 { &hf_icmpv6_checksum,
1911 { "Checksum", "icmpv6.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
1913 { &hf_icmpv6_checksum_bad,
1914 { "Bad Checksum", "icmpv6.checksum_bad", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1916 { &hf_icmpv6_haad_ha_addrs,
1917 { "Home Agent Addresses", "icmpv6.haad.ha_addrs",
1918 FT_IPv6, BASE_HEX, NULL, 0x0,
1921 static gint *ett[] = {
1926 &ett_nodeinfo_subject4,
1927 &ett_nodeinfo_subject6,
1928 &ett_nodeinfo_node4,
1929 &ett_nodeinfo_node6,
1930 &ett_nodeinfo_nodebitmap,
1931 &ett_nodeinfo_nodedns,
1935 proto_icmpv6 = proto_register_protocol("Internet Control Message Protocol v6",
1936 "ICMPv6", "icmpv6");
1937 proto_register_field_array(proto_icmpv6, hf, array_length(hf));
1938 proto_register_subtree_array(ett, array_length(ett));
1942 proto_reg_handoff_icmpv6(void)
1944 dissector_handle_t icmpv6_handle;
1946 icmpv6_handle = create_dissector_handle(dissect_icmpv6, proto_icmpv6);
1947 dissector_add("ip.proto", IP_PROTO_ICMPV6, icmpv6_handle);
1950 * Get a handle for the IPv6 dissector.
1952 ipv6_handle = find_dissector("ipv6");
1953 data_handle = find_dissector("data");