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>
11 * Copyright 2006, Nicolas DICHTEL - 6WIND - <nicolas.dichtel@6wind.com>
13 * HMIPv6 support added by Martti Kuparinen <martti.kuparinen@iki.fi>
15 * FMIPv6 support added by Martin Andre <andre@clarinet.u-strasbg.fr>
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License
19 * as published by the Free Software Foundation; either version 2
20 * of the License, or (at your option) any later version.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
47 #include <epan/packet.h>
48 #include "packet-ipv6.h"
49 #include "packet-dns.h"
50 #include <epan/in_cksum.h>
51 #include <epan/addr_resolv.h>
52 #include <epan/ipproto.h>
53 #include <epan/emem.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
77 static int proto_icmpv6 = -1;
78 static int hf_icmpv6_type = -1;
79 static int hf_icmpv6_code = -1;
80 static int hf_icmpv6_checksum = -1;
81 static int hf_icmpv6_checksum_bad = -1;
82 static int hf_icmpv6_haad_ha_addrs = -1;
83 static int hf_icmpv6_ra_cur_hop_limit = -1;
84 static int hf_icmpv6_ra_router_lifetime = -1;
85 static int hf_icmpv6_ra_reachable_time = -1;
86 static int hf_icmpv6_ra_retrans_timer = -1;
88 static int hf_icmpv6_option = -1;
89 static int hf_icmpv6_option_type = -1;
90 static int hf_icmpv6_option_length = -1;
92 static gint ett_icmpv6 = -1;
93 static gint ett_icmpv6opt = -1;
94 static gint ett_icmpv6flag = -1;
95 static gint ett_nodeinfo_flag = -1;
96 static gint ett_nodeinfo_subject4 = -1;
97 static gint ett_nodeinfo_subject6 = -1;
98 static gint ett_nodeinfo_node4 = -1;
99 static gint ett_nodeinfo_node6 = -1;
100 static gint ett_nodeinfo_nodebitmap = -1;
101 static gint ett_nodeinfo_nodedns = -1;
102 static gint ett_multicastRR = -1;
104 static dissector_handle_t ipv6_handle;
105 static dissector_handle_t data_handle;
107 static const value_string names_nodeinfo_qtype[] = {
108 { NI_QTYPE_NOOP, "NOOP" },
109 { NI_QTYPE_SUPTYPES, "Supported query types" },
110 { NI_QTYPE_DNSNAME, "DNS name" },
111 { NI_QTYPE_NODEADDR, "Node addresses" },
112 { NI_QTYPE_IPV4ADDR, "IPv4 node addresses" },
116 static const value_string names_rrenum_matchcode[] = {
117 { RPM_PCO_ADD, "Add" },
118 { RPM_PCO_CHANGE, "Change" },
119 { RPM_PCO_SETGLOBAL, "Set Global" },
123 static const value_string names_router_pref[] = {
124 { ND_RA_FLAG_RTPREF_HIGH, "High" },
125 { ND_RA_FLAG_RTPREF_MEDIUM, "Medium" },
126 { ND_RA_FLAG_RTPREF_LOW, "Low" },
127 { ND_RA_FLAG_RTPREF_RSV, "Reserved" },
131 static const value_string names_fmip6_prrtadv_code[] = {
132 { FMIP6_PRRTADV_MNTUP, "MN should use AP-ID, AR-info tuple" },
133 { FMIP6_PRRTADV_NI_HOVER, "Network Initiated Handover trigger" },
134 { FMIP6_PRRTADV_NORTINFO, "No new router information" },
135 { FMIP6_PRRTADV_LIMRTINFO, "Limited new router information" },
136 { FMIP6_PRRTADV_UNSOL, "Unsolicited" },
140 static const value_string names_fmip6_hi_code[] = {
141 { FMIP6_HI_PCOA, "FBU sent from previous link" },
142 { FMIP6_HI_NOTPCOA, "FBU sent from new link" },
146 static const value_string names_fmip6_hack_code[] = {
147 { FMIP6_HACK_VALID, "Handover Accepted, NCoA valid" },
148 { FMIP6_HACK_INVALID, "Handover Accepted, NCoA not valid" },
149 { FMIP6_HACK_INUSE, "Handover Accepted, NCoA in use" },
150 { FMIP6_HACK_ASSIGNED, "Handover Accepted, NCoA assigned" },
151 { FMIP6_HACK_NOTASSIGNED, "Handover Accepted, NCoA not assigned" },
152 { FMIP6_HACK_NOTACCEPTED, "Handover Not Accepted, reason unspecified" },
153 { FMIP6_HACK_PROHIBITED, "Administratively prohibited" },
154 { FMIP6_HACK_INSUFFICIENT, "Insufficient resources" },
158 static const value_string names_fmip6_ip_addr_opt_code[] = {
159 { FMIP6_OPT_IP_ADDRESS_OPTCODE_PCOA, "Old Care-of Address" },
160 { FMIP6_OPT_IP_ADDRESS_OPTCODE_NCOA, "New Care-of Address" },
161 { FMIP6_OPT_IP_ADDRESS_OPTCODE_NAR, "NAR's IP address" },
165 static const value_string names_fmip6_lla_opt_code[] = {
166 { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_WILDCARD, "Wildcard" },
167 { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_NAP, "Link-layer Address of the New Access Point" },
168 { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_MN, "Link-layer Address of the MN" },
169 { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_NAR, "Link-layer Address of the NAR" },
170 { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_SRC, "Link-layer Address of the source" },
171 { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_CURROUTER, "The AP belongs to the current interface of the router" },
172 { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_NOPREFIX, "No prefix information available" },
173 { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_NOSUPPORT, "No fast handovers support available" },
177 static const value_string names_fmip6_naack_opt_status[] = {
178 { FMIP6_OPT_NEIGHBOR_ADV_ACK_STATUS_INVALID, "New CoA is invalid" },
179 { FMIP6_OPT_NEIGHBOR_ADV_ACK_STATUS_INVALID_NEW, "New CoA is invalid, use the supplied CoA" },
180 { FMIP6_OPT_NEIGHBOR_ADV_ACK_STATUS_UNRECOGNIZED, "LLA is unrecognized" },
184 static const value_string option_vals[] = {
185 { ND_OPT_SOURCE_LINKADDR, "Source link-layer address" },
186 { ND_OPT_TARGET_LINKADDR, "Target link-layer address" },
187 { ND_OPT_PREFIX_INFORMATION, "Prefix information" },
188 { ND_OPT_REDIRECTED_HEADER, "Redirected header" },
189 { ND_OPT_MTU, "MTU" },
190 { ND_OPT_ADVINTERVAL, "Advertisement Interval" },
191 { ND_OPT_HOMEAGENT_INFO, "Home Agent Information" },
192 { ND_OPT_MAP, "HMIPv6 MAP option" },
193 { FMIP6_OPT_NEIGHBOR_ADV_ACK, "Neighbor Advertisement Acknowledgment" },
198 dissect_contained_icmpv6(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
200 gboolean save_in_error_pkt;
203 /* Save the current value of the "we're inside an error packet"
204 flag, and set that flag; subdissectors may treat packets
205 that are the payload of error packets differently from
207 save_in_error_pkt = pinfo->in_error_pkt;
208 pinfo->in_error_pkt = TRUE;
210 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
212 /* tiny sanity check */
213 if ((tvb_get_guint8(tvb, offset) & 0xf0) == 0x60) {
214 /* The contained packet is an IPv6 datagram; dissect it. */
215 call_dissector(ipv6_handle, next_tvb, pinfo, tree);
217 call_dissector(data_handle,next_tvb, pinfo, tree);
219 /* Restore the "we're inside an error packet" flag. */
220 pinfo->in_error_pkt = save_in_error_pkt;
224 dissect_icmpv6ndopt(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
226 proto_tree *icmp6opt_tree, *field_tree;
228 struct nd_opt_hdr nd_opt_hdr, *opt;
230 const char *typename;
231 static const guint8 nd_redirect_reserved[6] = {0, 0, 0, 0, 0, 0};
232 guint8 nd_redirect_res[6];
238 if ((int)tvb_reported_length(tvb) <= offset)
239 return; /* No more options left */
242 tvb_memcpy(tvb, (guint8 *)opt, offset, sizeof *opt);
243 len = opt->nd_opt_len << 3;
245 /* !!! specify length */
246 ti = proto_tree_add_item(tree, hf_icmpv6_option, tvb, offset, len, FALSE);
247 icmp6opt_tree = proto_item_add_subtree(ti, ett_icmpv6opt);
250 proto_tree_add_text(icmp6opt_tree, tvb,
251 offset + offsetof(struct nd_opt_hdr, nd_opt_len), 1,
252 "Invalid option length: %u",
254 return; /* we must not try to decode this */
257 typename = val_to_str(opt->nd_opt_type, option_vals, "Unknown");
259 /* Add option name to option root label */
260 proto_item_append_text(ti, " (%s)", typename);
263 proto_tree_add_uint(icmp6opt_tree, hf_icmpv6_option_type, tvb,
264 offset + offsetof(struct nd_opt_hdr, nd_opt_type), 1,
267 proto_tree_add_uint(icmp6opt_tree, hf_icmpv6_option_length, tvb,
268 offset + offsetof(struct nd_opt_hdr, nd_opt_len), 1,
269 opt->nd_opt_len << 3);
272 switch (opt->nd_opt_type) {
273 case ND_OPT_SOURCE_LINKADDR:
274 case ND_OPT_TARGET_LINKADDR:
278 p = offset + sizeof(*opt);
279 len = (opt->nd_opt_len << 3) - sizeof(*opt);
280 proto_tree_add_text(icmp6opt_tree, tvb,
281 offset + sizeof(*opt), len, "Link-layer address: %s",
282 bytestring_to_str(tvb_get_ptr(tvb, p, len), len, ':'));
285 case ND_OPT_PREFIX_INFORMATION:
287 struct nd_opt_prefix_info nd_opt_prefix_info, *pi;
290 pi = &nd_opt_prefix_info;
291 tvb_memcpy(tvb, (guint8 *)pi, offset, sizeof *pi);
292 proto_tree_add_text(icmp6opt_tree, tvb,
293 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_prefix_len),
294 1, "Prefix length: %u", pi->nd_opt_pi_prefix_len);
296 flagoff = offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_flags_reserved);
297 tf = proto_tree_add_text(icmp6opt_tree, tvb, flagoff, 1, "Flags: 0x%02x",
298 tvb_get_guint8(tvb, offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_flags_reserved)));
299 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
300 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
301 decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
302 ND_OPT_PI_FLAG_ONLINK, 8, "Onlink", "Not onlink"));
303 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
304 decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
305 ND_OPT_PI_FLAG_AUTO, 8, "Auto", "Not auto"));
306 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
307 decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
308 ND_OPT_PI_FLAG_ROUTER, 8,
309 "Router Address", "Not router address"));
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_SITEPREF, 8,
313 "Site prefix", "Not site prefix"));
314 if (pntohl(&pi->nd_opt_pi_valid_time) == 0xffffffff)
315 proto_tree_add_text(icmp6opt_tree, tvb,
316 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_valid_time),
317 4, "Valid lifetime: infinity");
319 proto_tree_add_text(icmp6opt_tree, tvb,
320 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_valid_time),
321 4, "Valid lifetime: %u",
322 pntohl(&pi->nd_opt_pi_valid_time));
323 if (pntohl(&pi->nd_opt_pi_preferred_time) == 0xffffffff)
324 proto_tree_add_text(icmp6opt_tree, tvb,
325 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_preferred_time),
326 4, "Preferred lifetime: infinity");
328 proto_tree_add_text(icmp6opt_tree, tvb,
329 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_preferred_time),
330 4, "Preferred lifetime: %u",
331 pntohl(&pi->nd_opt_pi_preferred_time));
332 proto_tree_add_text(icmp6opt_tree, tvb,
333 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_prefix),
334 16, "Prefix: %s", ip6_to_str(&pi->nd_opt_pi_prefix));
337 case ND_OPT_REDIRECTED_HEADER:
338 tvb_memcpy(tvb, (guint8 *)&nd_redirect_res, offset + 2, 6);
339 if (memcmp(nd_redirect_res, nd_redirect_reserved, 6) == 0)
340 proto_tree_add_text(icmp6opt_tree, tvb,
341 offset + 2, 6, "Reserved: 0 (correct)");
343 proto_tree_add_text(icmp6opt_tree, tvb,
344 offset +2, 6, "Reserved: MUST be 0 (incorrect!)");
345 proto_tree_add_text(icmp6opt_tree, tvb,
346 offset + 8, (opt->nd_opt_len << 3) - 8, "Redirected packet");
347 dissect_contained_icmpv6(tvb, offset + 8, pinfo, icmp6opt_tree);
350 proto_tree_add_text(icmp6opt_tree, tvb,
351 offset + offsetof(struct nd_opt_mtu, nd_opt_mtu_mtu), 4,
352 "MTU: %u", tvb_get_ntohl(tvb, offset + offsetof(struct nd_opt_mtu, nd_opt_mtu_mtu)));
354 case ND_OPT_ADVINTERVAL:
355 proto_tree_add_text(icmp6opt_tree, tvb,
356 offset + offsetof(struct nd_opt_adv_int, nd_opt_adv_int_advint), 4,
357 "Advertisement Interval: %u",
358 tvb_get_ntohl(tvb, offset + offsetof(struct nd_opt_adv_int, nd_opt_adv_int_advint)));
360 case ND_OPT_HOMEAGENT_INFO:
362 struct nd_opt_ha_info pibuf, *pi;
365 tvb_memcpy(tvb, (guint8 *)pi, offset, sizeof *pi);
366 proto_tree_add_text(icmp6opt_tree, tvb,
367 offset + offsetof(struct nd_opt_ha_info, nd_opt_ha_info_ha_pref),
368 2, "Home Agent Preference: %d",
369 (gint16)pntohs(&pi->nd_opt_ha_info_ha_pref));
370 proto_tree_add_text(icmp6opt_tree, tvb,
371 offset + offsetof(struct nd_opt_ha_info, nd_opt_ha_info_ha_life),
372 2, "Home Agent Lifetime: %u",
373 pntohs(&pi->nd_opt_ha_info_ha_life));
378 struct nd_opt_map_info mapbuf, *map;
382 tvb_memcpy(tvb, (guint8 *)map, offset, sizeof *map);
383 proto_tree_add_text(icmp6opt_tree, tvb,
384 offset + offsetof(struct nd_opt_map_info, nd_opt_map_dist_and_pref),
385 1, "Distance: %u", (map->nd_opt_map_dist_and_pref >> 4));
386 proto_tree_add_text(icmp6opt_tree, tvb,
387 offset + offsetof(struct nd_opt_map_info, nd_opt_map_dist_and_pref),
388 1, "Preference: %u", (map->nd_opt_map_dist_and_pref & 0x0F));
389 flagoff = offset + offsetof(struct nd_opt_map_info,
391 tf = proto_tree_add_text(icmp6opt_tree, tvb, flagoff, 1,
393 tvb_get_guint8(tvb, offset + offsetof(struct nd_opt_map_info,
395 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
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_R, 8, "R", "No R"));
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_M, 8, "M", "No M"));
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_I, 8, "I", "No I"));
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_T, 8, "T", "No T"));
408 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
409 decode_boolean_bitfield(map->nd_opt_map_flags,
410 ND_OPT_MAP_FLAG_P, 8, "P", "No P"));
411 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
412 decode_boolean_bitfield(map->nd_opt_map_flags,
413 ND_OPT_MAP_FLAG_V, 8, "V", "No V"));
414 proto_tree_add_text(icmp6opt_tree, tvb,
415 offset + offsetof(struct nd_opt_map_info, nd_opt_map_lifetime),
416 4, "Lifetime: %u", pntohl(&map->nd_opt_map_lifetime));
418 proto_tree_add_text(icmp6opt_tree, tvb,
419 offset + offsetof(struct nd_opt_map_info, nd_opt_map_address), 16,
421 "Address of MAP: %s (%s)",
422 get_hostname6(&map->nd_opt_map_address),
424 "Address of MAP: %s",
426 ip6_to_str(&map->nd_opt_map_address));
429 case ND_OPT_ROUTE_INFO:
431 struct nd_opt_route_info ribuf, *ri;
432 struct e_in6_addr in6;
437 tvb_memcpy(tvb, (guint8 *)ri, offset, sizeof *ri);
438 memset(&in6, 0, sizeof(in6));
439 switch (ri->nd_opt_rti_len) {
444 tvb_memcpy(tvb, (guint8 *)&in6, offset + sizeof(*ri), l = 8);
447 tvb_memcpy(tvb, (guint8 *)&in6, offset + sizeof(*ri), l = 16);
454 proto_tree_add_text(icmp6opt_tree, tvb,
455 offset + offsetof(struct nd_opt_route_info, nd_opt_rti_prefixlen),
456 1, "Prefix length: %u", ri->nd_opt_rti_prefixlen);
457 tf = proto_tree_add_text(icmp6opt_tree, tvb,
458 offset + offsetof(struct nd_opt_route_info, nd_opt_rti_flags),
459 1, "Flags: 0x%02x", ri->nd_opt_rti_flags);
460 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
461 proto_tree_add_text(field_tree, tvb,
462 offset + offsetof(struct nd_opt_route_info, nd_opt_rti_flags),
464 decode_enumerated_bitfield(ri->nd_opt_rti_flags,
465 ND_RA_FLAG_RTPREF_MASK, 8, names_router_pref,
466 "Router preference: %s"));
467 lifetime = pntohl(&ri->nd_opt_rti_lifetime);
468 if (lifetime == 0xffffffff)
469 proto_tree_add_text(icmp6opt_tree, tvb,
470 offset + offsetof(struct nd_opt_route_info, nd_opt_rti_lifetime),
471 sizeof(ri->nd_opt_rti_lifetime), "Lifetime: infinity");
473 proto_tree_add_text(icmp6opt_tree, tvb,
474 offset + offsetof(struct nd_opt_route_info, nd_opt_rti_lifetime),
475 sizeof(ri->nd_opt_rti_lifetime), "Lifetime: %u", lifetime);
476 proto_tree_add_text(icmp6opt_tree, tvb,
477 offset + sizeof(*ri), l, "Prefix: %s", ip6_to_str(&in6));
479 proto_tree_add_text(icmp6opt_tree, tvb,
480 offset + offsetof(struct nd_opt_hdr, nd_opt_len), 1,
481 "Invalid option length: %u", opt->nd_opt_len);
486 case FMIP6_OPT_NEIGHBOR_ADV_ACK:
488 struct fmip6_opt_neighbor_advertisement_ack fmip6_opt_neighbor_advertisement_ack, *opt_naack;
489 struct e_in6_addr in6;
491 opt_naack = &fmip6_opt_neighbor_advertisement_ack;
492 tvb_memcpy(tvb, (guint8 *)opt_naack, offset, sizeof *opt_naack);
494 proto_tree_add_text(icmp6opt_tree, tvb,
495 offset + offsetof(struct fmip6_opt_neighbor_advertisement_ack, fmip6_opt_optcode),
496 1, "Option-Code: %u",
497 opt_naack->fmip6_opt_optcode);
499 proto_tree_add_text(icmp6opt_tree, tvb,
500 offset + offsetof(struct fmip6_opt_neighbor_advertisement_ack, fmip6_opt_status),
502 val_to_str(opt_naack->fmip6_opt_status, names_fmip6_naack_opt_status, "Unknown"));
504 if (opt_naack->fmip6_opt_len == 3)
506 tvb_memcpy(tvb, (guint8 *)&in6, offset + sizeof(*opt_naack), 16);
507 proto_tree_add_text(icmp6opt_tree, tvb,
508 offset + sizeof(*opt_naack),
509 16, "New Care-of Address: %s",
517 offset += (opt->nd_opt_len << 3);
519 /* Set length of option tree */
520 proto_item_set_len(ti, opt->nd_opt_len << 3);
525 dissect_icmpv6fmip6opt(tvbuff_t *tvb, int offset, proto_tree *tree)
527 proto_tree *icmp6opt_tree;
529 struct fmip6_opt_hdr fmip6_opt_hdr, *opt;
537 if ((int)tvb_reported_length(tvb) <= offset)
538 return; /* No more options left */
540 opt = &fmip6_opt_hdr;
541 tvb_memcpy(tvb, (guint8 *)opt, offset, sizeof *opt);
542 len = opt->fmip6_opt_len << 3;
544 /* !!! specify length */
545 ti = proto_tree_add_text(tree, tvb, offset, len, "ICMPv6 options");
546 icmp6opt_tree = proto_item_add_subtree(ti, ett_icmpv6opt);
549 proto_tree_add_text(icmp6opt_tree, tvb,
550 offset + offsetof(struct fmip6_opt_hdr, fmip6_opt_len), 1,
551 "Invalid option length: %u",
553 return; /* we must not try to decode this */
556 switch (opt->fmip6_opt_type) {
557 case FMIP6_OPT_IP_ADDRESS:
558 typename = "IP Address";
560 case FMIP6_OPT_NEW_ROUTER_PREFIX_INFO:
561 typename = "New Router Prefix Information";
563 case FMIP6_OPT_LINK_LAYER_ADDRESS:
564 typename = "Link-layer Address";
567 typename = "Unknown";
571 proto_tree_add_text(icmp6opt_tree, tvb,
572 offset + offsetof(struct fmip6_opt_hdr, fmip6_opt_type), 1,
573 "Type: %u (%s)", opt->fmip6_opt_type, typename);
574 proto_tree_add_text(icmp6opt_tree, tvb,
575 offset + offsetof(struct fmip6_opt_hdr, fmip6_opt_len), 1,
576 "Length: %u bytes (%u)", opt->fmip6_opt_len << 3, opt->fmip6_opt_len);
579 switch (opt->fmip6_opt_type) {
580 case FMIP6_OPT_IP_ADDRESS:
582 struct fmip6_opt_ip_address fmip6_opt_ip_address, *opt_ip;
584 opt_ip = &fmip6_opt_ip_address;
585 tvb_memcpy(tvb, (guint8 *)opt_ip, offset, sizeof *opt_ip);
587 proto_tree_add_text(icmp6opt_tree, tvb,
588 offset + offsetof(struct fmip6_opt_hdr, fmip6_opt_optcode), 1, "Option-Code: %s",
589 val_to_str(opt->fmip6_opt_optcode, names_fmip6_ip_addr_opt_code, "Unknown"));
591 proto_tree_add_text(icmp6opt_tree, tvb,
592 offset + offsetof(struct fmip6_opt_ip_address, fmip6_opt_prefix_len),
593 1, "Prefix length: %u", opt_ip->fmip6_opt_prefix_len);
595 proto_tree_add_text(icmp6opt_tree, tvb,
596 offset + offsetof(struct fmip6_opt_ip_address, fmip6_opt_ip6_address),
597 16, "IPv6 Address: %s",
598 ip6_to_str(&opt_ip->fmip6_opt_ip6_address));
601 case FMIP6_OPT_NEW_ROUTER_PREFIX_INFO:
603 struct fmip6_opt_new_router_prefix_info fmip6_opt_new_router_prefix_info, *opt_nr;
605 opt_nr = &fmip6_opt_new_router_prefix_info;
606 tvb_memcpy(tvb, (guint8 *)opt_nr, offset, sizeof *opt_nr);
608 proto_tree_add_text(icmp6opt_tree, tvb,
609 offset + offsetof(struct fmip6_opt_hdr, fmip6_opt_optcode), 1, "Option-Code: %u",
610 opt->fmip6_opt_optcode);
612 proto_tree_add_text(icmp6opt_tree, tvb,
613 offset + offsetof(struct fmip6_opt_new_router_prefix_info, fmip6_opt_prefix_len),
614 1, "Prefix length: %u", opt_nr->fmip6_opt_prefix_len);
616 proto_tree_add_text(icmp6opt_tree, tvb,
617 offset + offsetof(struct fmip6_opt_new_router_prefix_info, fmip6_opt_prefix),
619 ip6_to_str(&opt_nr->fmip6_opt_prefix));
623 case FMIP6_OPT_LINK_LAYER_ADDRESS:
627 p = offset + sizeof(*opt);
628 proto_tree_add_text(icmp6opt_tree, tvb,
629 offset + offsetof(struct fmip6_opt_hdr, fmip6_opt_optcode), 1, "Option-Code: %s",
630 val_to_str(opt->fmip6_opt_optcode, names_fmip6_lla_opt_code, "Unknown"));
631 len = (opt->fmip6_opt_len << 3) - sizeof(*opt);
632 proto_tree_add_text(icmp6opt_tree, tvb,
633 offset + sizeof(*opt), len, "Link-layer address: %s",
634 bytestring_to_str(tvb_get_ptr(tvb, p, len), len, ':'));
639 offset += (opt->fmip6_opt_len << 3);
644 * draft-ietf-ipngwg-icmp-name-lookups-07.txt
645 * Note that the packet format was changed several times in the past.
649 bitrange0(guint32 v, int s, char *buf, int buflen)
665 ep = buf + buflen - 1;
666 memset(buf, 0, buflen);
669 /* shift till we have 0x01 */
670 if ((v & 0x01) == 0) {
673 v >>= 4; off += 4; continue;
675 v >>= 3; off += 3; continue;
676 case 0x04: case 0x0c:
677 v >>= 2; off += 2; continue;
679 v >>= 1; off += 1; continue;
683 /* we have 0x01 with us */
684 for (i = 0; i < 32 - off; i++) {
685 if ((v & (0x01 << i)) == 0)
689 l = g_snprintf(p, ep - p, ",%d", s + off);
691 l = g_snprintf(p, ep - p, ",%d-%d", s + off,
694 if (l == -1 || l >= ep - p) {
704 bitrange(tvbuff_t *tvb, int offset, int l, int s)
706 static char buf[1024];
710 memset(buf, 0, sizeof(buf));
712 eq = buf + sizeof(buf) - 1;
713 for (i = 0; i < l; i++) {
714 if (bitrange0(tvb_get_ntohl(tvb, offset + i * 4), s + i * 4, q, eq - q) == NULL) {
715 if (q != buf && q + 5 < buf + sizeof(buf))
716 strncpy(q, ",...", 5);
725 dissect_nodeinfo(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
727 proto_tree *field_tree;
729 struct icmp6_nodeinfo icmp6_nodeinfo, *ni;
737 ni = &icmp6_nodeinfo;
738 tvb_memcpy(tvb, (guint8 *)ni, offset, sizeof *ni);
740 flags = pntohs(&ni->ni_flags);
741 tf = proto_tree_add_text(tree, tvb,
742 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
743 sizeof(ni->ni_flags), "Flags: 0x%04x", flags);
744 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_flag);
745 switch (pntohs(&ni->ni_qtype)) {
746 case NI_QTYPE_SUPTYPES:
747 if (ni->ni_type == ICMP6_NI_QUERY) {
748 proto_tree_add_text(field_tree, tvb,
749 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
750 sizeof(ni->ni_flags), "%s",
751 decode_boolean_bitfield(flags, NI_SUPTYPE_FLAG_COMPRESS, sizeof(flags) * 8,
752 "Compressed reply supported",
753 "No compressed reply support"));
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_SUPTYPE_FLAG_COMPRESS, sizeof(flags) * 8,
759 "Compressed", "Not compressed"));
762 case NI_QTYPE_DNSNAME:
763 if (ni->ni_type == ICMP6_NI_REPLY) {
764 proto_tree_add_text(field_tree, tvb,
765 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
766 sizeof(ni->ni_flags), "%s",
767 decode_boolean_bitfield(flags, NI_FQDN_FLAG_VALIDTTL, sizeof(flags) * 8,
768 "Valid TTL field", "Meaningless TTL field"));
771 case NI_QTYPE_NODEADDR:
772 proto_tree_add_text(field_tree, tvb,
773 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
774 sizeof(ni->ni_flags), "%s",
775 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_GLOBAL, sizeof(flags) * 8,
777 "Not global address"));
778 proto_tree_add_text(field_tree, tvb,
779 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
780 sizeof(ni->ni_flags), "%s",
781 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_SITELOCAL, sizeof(flags) * 8,
782 "Site-local address",
783 "Not site-local address"));
784 proto_tree_add_text(field_tree, tvb,
785 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
786 sizeof(ni->ni_flags), "%s",
787 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_LINKLOCAL, sizeof(flags) * 8,
788 "Link-local address",
789 "Not link-local address"));
790 proto_tree_add_text(field_tree, tvb,
791 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
792 sizeof(ni->ni_flags), "%s",
793 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_COMPAT, sizeof(flags) * 8,
794 "IPv4 compatible/mapped address",
795 "Not IPv4 compatible/mapped address"));
797 case NI_QTYPE_IPV4ADDR:
798 proto_tree_add_text(field_tree, tvb,
799 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
800 sizeof(ni->ni_flags), "%s",
801 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_ALL, sizeof(flags) * 8,
802 "All unicast address",
803 "Unicast addresses on the queried interface"));
804 proto_tree_add_text(field_tree, tvb,
805 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
806 sizeof(ni->ni_flags), "%s",
807 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_TRUNCATE, sizeof(flags) * 8,
808 "Truncated", "Not truncated"));
813 proto_tree_add_text(tree, tvb,
814 offset + offsetof(struct icmp6_nodeinfo, icmp6_ni_nonce[0]),
815 sizeof(ni->icmp6_ni_nonce), "Nonce: 0x%08x%08x",
816 pntohl(&ni->icmp6_ni_nonce[0]), pntohl(&ni->icmp6_ni_nonce[4]));
818 /* offset for "the rest of data" */
822 if (!tvb_bytes_exist(tvb, offset, sizeof(*ni)))
824 if (ni->ni_type == ICMP6_NI_QUERY) {
825 switch (ni->ni_code) {
826 case ICMP6_NI_SUBJ_IPV6:
827 n = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
828 n /= sizeof(struct e_in6_addr);
829 tf = proto_tree_add_text(tree, tvb,
830 offset + sizeof(*ni), -1, "IPv6 subject addresses");
831 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_subject6);
832 p = offset + sizeof *ni;
833 for (i = 0; i < n; i++) {
834 struct e_in6_addr e_in6_addr;
835 tvb_get_ipv6(tvb, p, &e_in6_addr);
836 proto_tree_add_text(field_tree, tvb,
837 p, sizeof(struct e_in6_addr),
838 "%s", ip6_to_str(&e_in6_addr));
839 p += sizeof(struct e_in6_addr);
841 off = tvb_length_remaining(tvb, offset);
843 case ICMP6_NI_SUBJ_FQDN:
844 l = get_dns_name(tvb, offset + sizeof(*ni),
845 offset + sizeof(*ni), &dname);
846 if (tvb_bytes_exist(tvb, offset + sizeof(*ni) + l, 1) &&
847 tvb_get_guint8(tvb, offset + sizeof(*ni) + l) == 0) {
849 proto_tree_add_text(tree, tvb, offset + sizeof(*ni), l,
850 "DNS label: %s (truncated)", dname);
852 proto_tree_add_text(tree, tvb, offset + sizeof(*ni), l,
853 "DNS label: %s", dname);
855 off = tvb_length_remaining(tvb, offset + sizeof(*ni) + l);
857 case ICMP6_NI_SUBJ_IPV4:
858 n = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
859 n /= sizeof(guint32);
860 tf = proto_tree_add_text(tree, tvb,
861 offset + sizeof(*ni), -1, "IPv4 subject addresses");
862 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_subject4);
863 p = offset + sizeof *ni;
864 for (i = 0; i < n; i++) {
865 ipaddr = tvb_get_ipv4(tvb, p);
866 proto_tree_add_text(field_tree, tvb,
867 p, sizeof(guint32), "%s", ip_to_str((guint8 *)&ipaddr));
868 p += sizeof(guint32);
870 off = tvb_length_remaining(tvb, offset);
874 switch (pntohs(&ni->ni_qtype)) {
877 case NI_QTYPE_SUPTYPES:
878 p = offset + sizeof *ni;
879 tf = proto_tree_add_text(tree, tvb,
880 offset + sizeof(*ni), -1,
881 "Supported type bitmap%s",
882 (flags & 0x0001) ? ", compressed" : "");
883 field_tree = proto_item_add_subtree(tf,
884 ett_nodeinfo_nodebitmap);
886 while (tvb_bytes_exist(tvb, p, sizeof(guint32))) { /* XXXX Check what? */
887 if ((flags & 0x0001) == 0) {
888 l = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
889 l /= sizeof(guint32);
892 l = tvb_get_ntohs(tvb, p);
893 i = tvb_get_ntohs(tvb, p + sizeof(guint16)); /*skip*/
895 if (n + l * 32 > (1 << 16))
897 if (n + (l + i) * 32 > (1 << 16))
899 if ((flags & 0x0001) == 0) {
900 proto_tree_add_text(field_tree, tvb, p,
901 l * 4, "Bitmap (%d to %d): %s", n, n + l * 32 - 1,
902 bitrange(tvb, p, l, n));
905 proto_tree_add_text(field_tree, tvb, p,
906 4 + l * 4, "Bitmap (%d to %d): %s", n, n + l * 32 - 1,
907 bitrange(tvb, p + 4, l, n));
910 n += l * 32 + i * 32;
912 off = tvb_length_remaining(tvb, offset);
914 case NI_QTYPE_DNSNAME:
915 proto_tree_add_text(tree, tvb, offset + sizeof(*ni),
916 sizeof(gint32), "TTL: %d", (gint32)tvb_get_ntohl(tvb, offset + sizeof *ni));
917 tf = proto_tree_add_text(tree, tvb,
918 offset + sizeof(*ni) + sizeof(guint32), -1,
920 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_nodedns);
921 j = offset + sizeof (*ni) + sizeof(guint32);
922 while (j < tvb_reported_length(tvb)) {
923 l = get_dns_name(tvb, j,
924 offset + sizeof (*ni) + sizeof(guint32),
926 if (tvb_bytes_exist(tvb, j + l, 1) &&
927 tvb_get_guint8(tvb, j + l) == 0) {
929 proto_tree_add_text(field_tree, tvb, j, l,
930 "DNS label: %s (truncated)", dname);
932 proto_tree_add_text(field_tree, tvb, j, l,
933 "DNS label: %s", dname);
937 off = tvb_length_remaining(tvb, offset);
939 case NI_QTYPE_NODEADDR:
940 n = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
941 n /= sizeof(gint32) + sizeof(struct e_in6_addr);
942 tf = proto_tree_add_text(tree, tvb,
943 offset + sizeof(*ni), -1, "IPv6 node addresses");
944 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_node6);
945 p = offset + sizeof (*ni);
946 for (i = 0; i < n; i++) {
947 struct e_in6_addr e_in6_addr;
949 ttl = (gint32)tvb_get_ntohl(tvb, p);
950 tvb_get_ipv6(tvb, p + sizeof ttl, &e_in6_addr);
951 proto_tree_add_text(field_tree, tvb,
952 p, sizeof(struct e_in6_addr) + sizeof(gint32),
953 "%s (TTL %d)", ip6_to_str(&e_in6_addr), ttl);
954 p += sizeof(struct e_in6_addr) + sizeof(gint32);
956 off = tvb_length_remaining(tvb, offset);
958 case NI_QTYPE_IPV4ADDR:
959 n = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
960 n /= sizeof(gint32) + sizeof(guint32);
961 tf = proto_tree_add_text(tree, tvb,
962 offset + sizeof(*ni), -1, "IPv4 node addresses");
963 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_node4);
964 p = offset + sizeof *ni;
965 for (i = 0; i < n; i++) {
966 ipaddr = tvb_get_ipv4(tvb, sizeof(gint32) + p);
967 proto_tree_add_text(field_tree, tvb,
968 p, sizeof(guint32), "%s (TTL %d)",
969 ip_to_str((guint8 *)&ipaddr), tvb_get_ntohl(tvb, p));
970 p += sizeof(gint32) + sizeof(guint32);
972 off = tvb_length_remaining(tvb, offset);
978 /* the rest of data */
979 call_dissector(data_handle,tvb_new_subset(tvb, offset + off, -1, -1), pinfo, tree);
983 dissect_rrenum(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
985 proto_tree *field_tree, *opt_tree;
987 struct icmp6_router_renum icmp6_router_renum, *rr;
988 struct rr_pco_match rr_pco_match, *match;
989 struct rr_pco_use rr_pco_use, *use;
994 rr = &icmp6_router_renum;
995 tvb_memcpy(tvb, (guint8 *)rr, offset, sizeof *rr);
996 proto_tree_add_text(tree, tvb,
997 offset + offsetof(struct icmp6_router_renum, rr_seqnum), 4,
998 "Sequence number: 0x%08x", pntohl(&rr->rr_seqnum));
999 proto_tree_add_text(tree, tvb,
1000 offset + offsetof(struct icmp6_router_renum, rr_segnum), 1,
1001 "Segment number: 0x%02x", rr->rr_segnum);
1003 flagoff = offset + offsetof(struct icmp6_router_renum, rr_flags);
1004 flags = tvb_get_guint8(tvb, flagoff);
1005 tf = proto_tree_add_text(tree, tvb, flagoff, 1,
1006 "Flags: 0x%02x", flags);
1007 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1008 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1009 decode_boolean_bitfield(flags, 0x80, 8,
1010 "Test command", "Not test command"));
1011 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1012 decode_boolean_bitfield(flags, 0x40, 8,
1013 "Result requested", "Result not requested"));
1014 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1015 decode_boolean_bitfield(flags, 0x20, 8,
1016 "All interfaces", "Not all interfaces"));
1017 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1018 decode_boolean_bitfield(flags, 0x10, 8,
1019 "Site specific", "Not site specific"));
1020 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1021 decode_boolean_bitfield(flags, 0x08, 8,
1022 "Processed previously", "Complete result"));
1024 proto_tree_add_text(tree, tvb,
1025 offset + offsetof(struct icmp6_router_renum, rr_maxdelay), 2,
1026 "Max delay: 0x%04x", pntohs(&rr->rr_maxdelay));
1027 call_dissector(data_handle,tvb_new_subset(tvb, offset + sizeof(*rr), -1, -1), pinfo, tree); /*XXX*/
1029 if (rr->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) {
1030 off = offset + sizeof(*rr);
1031 match = &rr_pco_match;
1032 tvb_memcpy(tvb, (guint8 *)match, off, sizeof *match);
1033 tf = proto_tree_add_text(tree, tvb, off, sizeof(*match),
1034 "Match-Prefix: %s/%u (%u-%u)", ip6_to_str(&match->rpm_prefix),
1035 match->rpm_matchlen, match->rpm_minlen, match->rpm_maxlen);
1036 opt_tree = proto_item_add_subtree(tf, ett_icmpv6opt);
1037 proto_tree_add_text(opt_tree, tvb,
1038 off + offsetof(struct rr_pco_match, rpm_code),
1039 sizeof(match->rpm_code), "OpCode: %s (%u)",
1040 val_to_str(match->rpm_code, names_rrenum_matchcode, "Unknown"),
1042 proto_tree_add_text(opt_tree, tvb,
1043 off + offsetof(struct rr_pco_match, rpm_len),
1044 sizeof(match->rpm_len), "OpLength: %u (%u octets)",
1045 match->rpm_len, match->rpm_len * 8);
1046 proto_tree_add_text(opt_tree, tvb,
1047 off + offsetof(struct rr_pco_match, rpm_ordinal),
1048 sizeof(match->rpm_ordinal), "Ordinal: %u", match->rpm_ordinal);
1049 proto_tree_add_text(opt_tree, tvb,
1050 off + offsetof(struct rr_pco_match, rpm_matchlen),
1051 sizeof(match->rpm_matchlen), "MatchLen: %u", match->rpm_matchlen);
1052 proto_tree_add_text(opt_tree, tvb,
1053 off + offsetof(struct rr_pco_match, rpm_minlen),
1054 sizeof(match->rpm_minlen), "MinLen: %u", match->rpm_minlen);
1055 proto_tree_add_text(opt_tree, tvb,
1056 off + offsetof(struct rr_pco_match, rpm_maxlen),
1057 sizeof(match->rpm_maxlen), "MaxLen: %u", match->rpm_maxlen);
1058 proto_tree_add_text(opt_tree, tvb,
1059 off + offsetof(struct rr_pco_match, rpm_prefix),
1060 sizeof(match->rpm_prefix), "MatchPrefix: %s",
1061 ip6_to_str(&match->rpm_prefix));
1063 off += sizeof(*match);
1065 for (l = match->rpm_len * 8 - sizeof(*match);
1066 l >= sizeof(*use); l -= sizeof(*use), off += sizeof(*use)) {
1067 tvb_memcpy(tvb, (guint8 *)use, off, sizeof *use);
1068 tf = proto_tree_add_text(tree, tvb, off, sizeof(*use),
1069 "Use-Prefix: %s/%u (keep %u)", ip6_to_str(&use->rpu_prefix),
1070 use->rpu_uselen, use->rpu_keeplen);
1071 opt_tree = proto_item_add_subtree(tf, ett_icmpv6opt);
1072 proto_tree_add_text(opt_tree, tvb,
1073 off + offsetof(struct rr_pco_use, rpu_uselen),
1074 sizeof(use->rpu_uselen), "UseLen: %u", use->rpu_uselen);
1075 proto_tree_add_text(opt_tree, tvb,
1076 off + offsetof(struct rr_pco_use, rpu_keeplen),
1077 sizeof(use->rpu_keeplen), "KeepLen: %u", use->rpu_keeplen);
1078 tf = proto_tree_add_text(opt_tree, tvb,
1079 flagoff = off + offsetof(struct rr_pco_use, rpu_ramask),
1080 sizeof(use->rpu_ramask), "FlagMask: 0x%x", use->rpu_ramask);
1081 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1082 flags = tvb_get_guint8(tvb, flagoff);
1083 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1084 decode_boolean_bitfield(flags,
1085 ICMP6_RR_PCOUSE_RAFLAGS_ONLINK, 8,
1086 "Onlink", "Not onlink"));
1087 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1088 decode_boolean_bitfield(flags,
1089 ICMP6_RR_PCOUSE_RAFLAGS_AUTO, 8,
1090 "Auto", "Not auto"));
1091 tf = proto_tree_add_text(opt_tree, tvb,
1092 flagoff = off + offsetof(struct rr_pco_use, rpu_raflags),
1093 sizeof(use->rpu_raflags), "RAFlags: 0x%x", use->rpu_raflags);
1094 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1095 flags = tvb_get_guint8(tvb, flagoff);
1096 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1097 decode_boolean_bitfield(flags,
1098 ICMP6_RR_PCOUSE_RAFLAGS_ONLINK, 8,
1099 "Onlink", "Not onlink"));
1100 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1101 decode_boolean_bitfield(flags,
1102 ICMP6_RR_PCOUSE_RAFLAGS_AUTO, 8, "Auto", "Not auto"));
1103 if (pntohl(&use->rpu_vltime) == 0xffffffff)
1104 proto_tree_add_text(opt_tree, tvb,
1105 off + offsetof(struct rr_pco_use, rpu_vltime),
1106 sizeof(use->rpu_vltime), "Valid Lifetime: infinity");
1108 proto_tree_add_text(opt_tree, tvb,
1109 off + offsetof(struct rr_pco_use, rpu_vltime),
1110 sizeof(use->rpu_vltime), "Valid Lifetime: %u",
1111 pntohl(&use->rpu_vltime));
1112 if (pntohl(&use->rpu_pltime) == 0xffffffff)
1113 proto_tree_add_text(opt_tree, tvb,
1114 off + offsetof(struct rr_pco_use, rpu_pltime),
1115 sizeof(use->rpu_pltime), "Preferred Lifetime: infinity");
1117 proto_tree_add_text(opt_tree, tvb,
1118 off + offsetof(struct rr_pco_use, rpu_pltime),
1119 sizeof(use->rpu_pltime), "Preferred Lifetime: %u",
1120 pntohl(&use->rpu_pltime));
1121 tf = proto_tree_add_text(opt_tree, tvb,
1122 flagoff = off + offsetof(struct rr_pco_use, rpu_flags),
1123 sizeof(use->rpu_flags), "Flags: 0x%08x",
1124 pntohl(&use->rpu_flags));
1125 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1126 flags = tvb_get_guint8(tvb, flagoff);
1127 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
1128 decode_boolean_bitfield(flags,
1129 ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, 32,
1130 "Decrement valid lifetime", "No decrement valid lifetime"));
1131 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
1132 decode_boolean_bitfield(flags,
1133 ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, 32,
1134 "Decrement preferred lifetime",
1135 "No decrement preferred lifetime"));
1136 proto_tree_add_text(opt_tree, tvb,
1137 off + offsetof(struct rr_pco_use, rpu_prefix),
1138 sizeof(use->rpu_prefix), "UsePrefix: %s",
1139 ip6_to_str(&use->rpu_prefix));
1146 * See I-D draft-vida-mld-v2-08
1148 static const value_string mldrv2ModesNames[] = {
1151 { 3, "Changed to include" },
1152 { 4, "Changed to exclude" },
1153 { 5, "Allow new sources" },
1154 { 6, "Block old sources" },
1159 dissect_mldrv2( tvbuff_t *tvb, guint32 offset, guint16 count, proto_tree *tree )
1161 proto_tree *sub_tree;
1164 guint8 recordType, auxDataLen;
1165 guint32 sourceNb, recordSize, localOffset;
1166 struct e_in6_addr addr;
1168 for( ; count; count--, offset += recordSize ) {
1169 localOffset = offset;
1170 recordType = tvb_get_guint8( tvb, localOffset );
1172 auxDataLen = tvb_get_guint8( tvb, localOffset );
1174 sourceNb = tvb_get_ntohs( tvb, localOffset );
1176 recordSize = 4 + 16 + (16 * sourceNb) + (auxDataLen * 4);
1178 tvb_get_ipv6(tvb, localOffset, &addr);
1179 tf = proto_tree_add_text( tree, tvb, offset, recordSize,
1181 "%s: %s (%s)", val_to_str(recordType, mldrv2ModesNames,"Unknown mode"),
1182 get_hostname6(&addr), ip6_to_str(&addr)
1184 "%s: %s", val_to_str(recordType, mldrv2ModesNames,"Unknown mode"),
1188 sub_tree = proto_item_add_subtree(tf, ett_multicastRR);
1190 proto_tree_add_text( sub_tree, tvb, offset, 1, "Mode: %s",
1191 val_to_str(recordType, mldrv2ModesNames,"Unknown mode") );
1192 proto_tree_add_text( sub_tree, tvb, offset+1, 1, "Aux data len: %u", auxDataLen * 4);
1193 proto_tree_add_text( sub_tree, tvb, localOffset, 16, "Multicast Address: %s", ip6_to_str(&addr) );
1196 for( ; sourceNb; sourceNb--, localOffset += 16 ) {
1197 tvb_get_ipv6(tvb, localOffset, &addr);
1198 proto_tree_add_text( sub_tree, tvb, localOffset, 16,
1200 "Source Address: %s (%s)", get_hostname6(&addr), ip6_to_str(&addr) );
1202 "Source Address: %s", ip6_to_str(&addr) );
1209 dissect_mldqv2(tvbuff_t *tvb, guint32 offset, guint16 count, proto_tree *tree)
1211 struct e_in6_addr addr;
1213 for ( ; count; count--, offset += 16) {
1214 tvb_get_ipv6(tvb, offset, &addr);
1215 proto_tree_add_text(tree, tvb, offset, 16,
1216 "Source Address: %s (%s)", get_hostname6(&addr), ip6_to_str(&addr));
1221 dissect_icmpv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1223 proto_tree *icmp6_tree, *field_tree;
1224 proto_item *ti, *tf = NULL;
1225 struct icmp6_hdr icmp6_hdr, *dp;
1226 struct icmp6_nodeinfo *ni = NULL;
1227 const char *codename, *typename;
1228 const char *colcodename, *coltypename;
1230 guint length, reported_length;
1233 guint16 cksum, computed_cksum;
1237 if (check_col(pinfo->cinfo, COL_PROTOCOL))
1238 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ICMPv6");
1239 if (check_col(pinfo->cinfo, COL_INFO))
1240 col_clear(pinfo->cinfo, COL_INFO);
1243 tvb_memcpy(tvb, (guint8 *)&icmp6_hdr, offset, sizeof icmp6_hdr);
1245 codename = typename = colcodename = coltypename = "Unknown";
1247 switch (dp->icmp6_type) {
1248 case ICMP6_DST_UNREACH:
1249 typename = coltypename = "Unreachable";
1250 switch (dp->icmp6_code) {
1251 case ICMP6_DST_UNREACH_NOROUTE:
1252 codename = colcodename = "Route unreachable";
1254 case ICMP6_DST_UNREACH_ADMIN:
1255 codename = colcodename = "Administratively prohibited";
1257 case ICMP6_DST_UNREACH_NOTNEIGHBOR:
1258 codename = colcodename = "Not a neighbor";
1260 case ICMP6_DST_UNREACH_ADDR:
1261 codename = colcodename = "Address unreachable";
1263 case ICMP6_DST_UNREACH_NOPORT:
1264 codename = colcodename = "Port unreachable";
1268 case ICMP6_PACKET_TOO_BIG:
1269 typename = coltypename = "Too big";
1270 codename = colcodename = NULL;
1272 case ICMP6_TIME_EXCEEDED:
1273 typename = coltypename = "Time exceeded";
1274 switch (dp->icmp6_code) {
1275 case ICMP6_TIME_EXCEED_TRANSIT:
1276 codename = colcodename = "In-transit";
1278 case ICMP6_TIME_EXCEED_REASSEMBLY:
1279 codename = colcodename = "Reassembly";
1283 case ICMP6_PARAM_PROB:
1284 typename = coltypename = "Parameter problem";
1285 switch (dp->icmp6_code) {
1286 case ICMP6_PARAMPROB_HEADER:
1287 codename = colcodename = "Header";
1289 case ICMP6_PARAMPROB_NEXTHEADER:
1290 codename = colcodename = "Next header";
1292 case ICMP6_PARAMPROB_OPTION:
1293 codename = colcodename = "Option";
1297 case ICMP6_ECHO_REQUEST:
1298 typename = coltypename = "Echo request";
1299 codename = colcodename = NULL;
1301 case ICMP6_ECHO_REPLY:
1302 typename = coltypename = "Echo reply";
1303 codename = colcodename = NULL;
1305 case ICMP6_MEMBERSHIP_QUERY:
1306 typename = coltypename = "Multicast listener query";
1307 codename = colcodename = NULL;
1309 case ICMP6_MEMBERSHIP_REPORT:
1310 typename = coltypename = "Multicast listener report";
1311 codename = colcodename = NULL;
1313 case ICMP6_MEMBERSHIP_REDUCTION:
1314 typename = coltypename = "Multicast listener done";
1315 codename = colcodename = NULL;
1317 case ND_ROUTER_SOLICIT:
1318 typename = coltypename = "Router solicitation";
1319 codename = colcodename = NULL;
1320 len = sizeof(struct nd_router_solicit);
1322 case ND_ROUTER_ADVERT:
1323 typename = coltypename = "Router advertisement";
1324 codename = colcodename = NULL;
1325 len = sizeof(struct nd_router_advert);
1327 case ND_NEIGHBOR_SOLICIT:
1328 typename = coltypename = "Neighbor solicitation";
1329 codename = colcodename = NULL;
1330 len = sizeof(struct nd_neighbor_solicit);
1332 case ND_NEIGHBOR_ADVERT:
1333 typename = coltypename = "Neighbor advertisement";
1334 codename = colcodename = NULL;
1335 len = sizeof(struct nd_neighbor_advert);
1338 typename = coltypename = "Redirect";
1339 codename = colcodename = NULL;
1340 len = sizeof(struct nd_redirect);
1342 case ICMP6_ROUTER_RENUMBERING:
1343 typename = coltypename = "Router renumbering";
1344 switch (dp->icmp6_code) {
1345 case ICMP6_ROUTER_RENUMBERING_COMMAND:
1346 codename = colcodename = "Command";
1348 case ICMP6_ROUTER_RENUMBERING_RESULT:
1349 codename = colcodename = "Result";
1351 case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
1352 codename = colcodename = "Sequence number reset";
1355 len = sizeof(struct icmp6_router_renum);
1357 case ICMP6_NI_QUERY:
1358 case ICMP6_NI_REPLY:
1359 ni = (struct icmp6_nodeinfo *)dp;
1360 if (ni->ni_type == ICMP6_NI_QUERY) {
1361 typename = coltypename = "Node information query";
1362 switch (ni->ni_code) {
1363 case ICMP6_NI_SUBJ_IPV6:
1364 codename = "Query subject = IPv6 addresses";
1366 case ICMP6_NI_SUBJ_FQDN:
1367 if (tvb_bytes_exist(tvb, offset, sizeof(*ni)))
1368 codename = "Query subject = DNS name";
1370 codename = "Query subject = empty";
1372 case ICMP6_NI_SUBJ_IPV4:
1373 codename = "Query subject = IPv4 addresses";
1377 typename = coltypename = "Node information reply";
1378 switch (ni->ni_code) {
1379 case ICMP6_NI_SUCCESS:
1380 codename = "Successful";
1382 case ICMP6_NI_REFUSED:
1383 codename = "Refused";
1385 case ICMP6_NI_UNKNOWN:
1386 codename = "Unknown query type";
1390 colcodename = val_to_str(pntohs(&ni->ni_qtype), names_nodeinfo_qtype,
1392 len = sizeof(struct icmp6_nodeinfo);
1394 case ICMP6_MIP6_DHAAD_REQUEST:
1395 typename = coltypename = "Dynamic Home Agent Address Discovery Request";
1396 codename = "Should always be zero";
1399 case ICMP6_MIP6_DHAAD_REPLY:
1400 typename = coltypename = "Dynamic Home Agent Address Discovery Reply";
1401 codename = "Should always be zero";
1404 case ICMP6_MIP6_MPS:
1405 typename = coltypename = "Mobile Prefix Solicitation";
1406 codename = "Should always be zero";
1409 case ICMP6_MIP6_MPA:
1410 typename = coltypename = "Mobile Prefix Advertisement";
1411 codename = "Should always be zero";
1414 case ICMP6_MLDV2_REPORT:
1415 typename = coltypename = "Multicast Listener Report Message v2";
1416 codename = "Should always be zero";
1419 case ICMP6_EXPERIMENTAL_MOBILITY:
1420 typename = coltypename ="Experimental Mobility";
1421 switch (dp->icmp6_data8[0]) {
1422 case FMIP6_SUBTYPE_RTSOLPR:
1423 typename = coltypename ="RtSolPr (ICMPv6 Experimental Mobility)";
1424 codename = "Should always be zero";
1427 case FMIP6_SUBTYPE_PRRTADV:
1428 typename = coltypename ="PrRtAdv (ICMPv6 Experimental Mobility)";
1429 codename = val_to_str(dp->icmp6_code, names_fmip6_prrtadv_code, "Unknown");
1432 case FMIP6_SUBTYPE_HI:
1433 typename = coltypename ="HI (ICMPv6 Experimental Mobility)";
1434 codename = val_to_str(dp->icmp6_code, names_fmip6_hi_code, "Unknown");
1437 case FMIP6_SUBTYPE_HACK:
1438 typename = coltypename ="HAck (ICMPv6 Experimental Mobility)";
1439 codename = val_to_str(dp->icmp6_code, names_fmip6_hack_code, "Unknown");
1446 if (check_col(pinfo->cinfo, COL_INFO)) {
1447 char typebuf[256], codebuf[256];
1449 if (coltypename && strcmp(coltypename, "Unknown") == 0) {
1450 g_snprintf(typebuf, sizeof(typebuf), "Unknown (0x%02x)",
1452 coltypename = typebuf;
1454 if (colcodename && strcmp(colcodename, "Unknown") == 0) {
1455 g_snprintf(codebuf, sizeof(codebuf), "Unknown (0x%02x)",
1457 colcodename = codebuf;
1460 col_add_fstr(pinfo->cinfo, COL_INFO, "%s (%s)", coltypename, colcodename);
1462 col_add_fstr(pinfo->cinfo, COL_INFO, "%s", coltypename);
1467 /* !!! specify length */
1468 ti = proto_tree_add_item(tree, proto_icmpv6, tvb, offset, -1, FALSE);
1469 icmp6_tree = proto_item_add_subtree(ti, ett_icmpv6);
1471 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_type, tvb,
1472 offset + offsetof(struct icmp6_hdr, icmp6_type), 1,
1474 "Type: %u (%s)", dp->icmp6_type, typename);
1476 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_code, tvb,
1477 offset + offsetof(struct icmp6_hdr, icmp6_code), 1,
1479 "Code: %u (%s)", dp->icmp6_code, codename);
1481 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_code, tvb,
1482 offset + offsetof(struct icmp6_hdr, icmp6_code), 1,
1484 "Code: %u", dp->icmp6_code);
1486 cksum = (guint16)g_htons(dp->icmp6_cksum);
1487 length = tvb_length(tvb);
1488 reported_length = tvb_reported_length(tvb);
1489 if (!pinfo->fragmented && length >= reported_length) {
1490 /* The packet isn't part of a fragmented datagram and isn't
1491 truncated, so we can checksum it. */
1493 /* Set up the fields of the pseudo-header. */
1494 cksum_vec[0].ptr = pinfo->src.data;
1495 cksum_vec[0].len = pinfo->src.len;
1496 cksum_vec[1].ptr = pinfo->dst.data;
1497 cksum_vec[1].len = pinfo->dst.len;
1498 cksum_vec[2].ptr = (const guint8 *)&phdr;
1499 phdr[0] = g_htonl(tvb_reported_length(tvb));
1500 phdr[1] = g_htonl(IP_PROTO_ICMPV6);
1501 cksum_vec[2].len = 8;
1502 cksum_vec[3].len = tvb_reported_length(tvb);
1503 cksum_vec[3].ptr = tvb_get_ptr(tvb, offset, cksum_vec[3].len);
1504 computed_cksum = in_cksum(cksum_vec, 4);
1505 if (computed_cksum == 0) {
1506 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_checksum,
1508 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1510 "Checksum: 0x%04x [correct]", cksum);
1512 proto_tree_add_boolean_hidden(icmp6_tree, hf_icmpv6_checksum_bad,
1514 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1516 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_checksum,
1518 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1520 "Checksum: 0x%04x [incorrect, should be 0x%04x]",
1521 cksum, in_cksum_shouldbe(cksum, computed_cksum));
1524 proto_tree_add_uint(icmp6_tree, hf_icmpv6_checksum, tvb,
1525 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1530 switch (dp->icmp6_type) {
1531 case ICMP6_DST_UNREACH:
1532 case ICMP6_TIME_EXCEEDED:
1533 dissect_contained_icmpv6(tvb, offset + sizeof(*dp), pinfo,
1536 case ICMP6_PACKET_TOO_BIG:
1537 proto_tree_add_text(icmp6_tree, tvb,
1538 offset + offsetof(struct icmp6_hdr, icmp6_mtu), 4,
1539 "MTU: %u", pntohl(&dp->icmp6_mtu));
1540 dissect_contained_icmpv6(tvb, offset + sizeof(*dp), pinfo,
1543 case ICMP6_PARAM_PROB:
1544 proto_tree_add_text(icmp6_tree, tvb,
1545 offset + offsetof(struct icmp6_hdr, icmp6_pptr), 4,
1546 "Problem pointer: 0x%04x", pntohl(&dp->icmp6_pptr));
1547 dissect_contained_icmpv6(tvb, offset + sizeof(*dp), pinfo,
1550 case ICMP6_ECHO_REQUEST:
1551 case ICMP6_ECHO_REPLY:
1552 proto_tree_add_text(icmp6_tree, tvb,
1553 offset + offsetof(struct icmp6_hdr, icmp6_id), 2,
1554 "ID: 0x%04x", (guint16)g_ntohs(dp->icmp6_id));
1555 proto_tree_add_text(icmp6_tree, tvb,
1556 offset + offsetof(struct icmp6_hdr, icmp6_seq), 2,
1557 "Sequence: 0x%04x", (guint16)g_ntohs(dp->icmp6_seq));
1558 next_tvb = tvb_new_subset(tvb, offset + sizeof(*dp), -1, -1);
1559 call_dissector(data_handle,next_tvb, pinfo, icmp6_tree);
1561 case ICMP6_MEMBERSHIP_QUERY:
1562 case ICMP6_MEMBERSHIP_REPORT:
1563 case ICMP6_MEMBERSHIP_REDUCTION:
1564 #define MLDV2_MINLEN 28
1565 #define MLDV1_MINLEN 24
1566 if (dp->icmp6_type == ICMP6_MEMBERSHIP_QUERY) {
1567 if (length >= MLDV2_MINLEN) {
1573 mrc = g_ntohs(dp->icmp6_maxdelay);
1574 flag = tvb_get_guint8(tvb, offset + sizeof(*dp) + 16);
1575 qqi = tvb_get_guint8(tvb, offset + sizeof(*dp) + 16 + 1);
1576 nsrcs = tvb_get_ntohs(tvb, offset + sizeof(*dp) + 16 + 2);
1579 mrc = ((mrc & 0x0fff) | 0x1000) <<
1580 (((mrc & 0x7000) >> 12) + 3);
1581 proto_tree_add_text(icmp6_tree, tvb,
1582 offset + offsetof(struct icmp6_hdr, icmp6_maxdelay), 2,
1583 "Maximum response delay[ms]: %u", mrc);
1585 proto_tree_add_text(icmp6_tree, tvb, offset + sizeof(*dp),
1586 16, "Multicast Address: %s",
1587 ip6_to_str((const struct e_in6_addr *)(tvb_get_ptr(tvb,
1588 offset + sizeof *dp, sizeof (struct e_in6_addr)))));
1590 proto_tree_add_text(icmp6_tree, tvb,
1591 offset + sizeof(*dp) + 16, 1, "S Flag: %s",
1592 flag & 0x08 ? "ON" : "OFF");
1593 proto_tree_add_text(icmp6_tree, tvb,
1594 offset + sizeof(*dp) + 16, 1, "Robustness: %d",
1597 qqi = ((qqi & 0x0f) | 0x10) << (((qqi & 0x70) >> 4) + 3);
1598 proto_tree_add_text(icmp6_tree, tvb,
1599 offset + sizeof(*dp) + 17, 1, "QQI: %d", qqi);
1601 dissect_mldqv2(tvb, offset + sizeof(*dp) + 20, nsrcs,
1604 } else if (length > MLDV1_MINLEN) {
1605 next_tvb = tvb_new_subset(tvb, offset + sizeof(*dp), -1, -1);
1606 call_dissector(data_handle,next_tvb, pinfo, tree);
1609 /* MLDv1 Query -> FALLTHOUGH */
1613 proto_tree_add_text(icmp6_tree, tvb,
1614 offset + offsetof(struct icmp6_hdr, icmp6_maxdelay), 2,
1615 "Maximum response delay: %u",
1616 (guint16)g_ntohs(dp->icmp6_maxdelay));
1617 proto_tree_add_text(icmp6_tree, tvb, offset + sizeof(*dp), 16,
1618 "Multicast Address: %s",
1619 ip6_to_str((const struct e_in6_addr *)(tvb_get_ptr(tvb, offset + sizeof *dp, sizeof (struct e_in6_addr)))));
1621 case ND_ROUTER_SOLICIT:
1622 dissect_icmpv6ndopt(tvb, offset + sizeof(*dp), pinfo, icmp6_tree);
1624 case ICMP6_MLDV2_REPORT: {
1627 nbRecords = tvb_get_ntohs( tvb, offset+4+2 );
1628 dissect_mldrv2( tvb, offset+4+2+2, nbRecords, icmp6_tree );
1631 case ND_ROUTER_ADVERT:
1633 struct nd_router_advert nd_router_advert, *ra;
1637 ra = &nd_router_advert;
1638 tvb_memcpy(tvb, (guint8 *)ra, offset, sizeof *ra);
1640 /* Current hop limit */
1641 proto_tree_add_uint(icmp6_tree, hf_icmpv6_ra_cur_hop_limit, tvb,
1642 offset + offsetof(struct nd_router_advert, nd_ra_curhoplimit),
1643 1, ra->nd_ra_curhoplimit);
1646 flagoff = offset + offsetof(struct nd_router_advert, nd_ra_flags_reserved);
1647 ra_flags = tvb_get_guint8(tvb, flagoff);
1648 tf = proto_tree_add_text(icmp6_tree, tvb, flagoff, 1, "Flags: 0x%02x", ra_flags);
1649 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1651 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1652 decode_boolean_bitfield(ra_flags,
1653 ND_RA_FLAG_MANAGED, 8, "Managed", "Not managed"));
1654 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1655 decode_boolean_bitfield(ra_flags,
1656 ND_RA_FLAG_OTHER, 8, "Other", "Not other"));
1657 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1658 decode_boolean_bitfield(ra_flags,
1659 ND_RA_FLAG_HOME_AGENT, 8,
1660 "Home Agent", "Not Home Agent"));
1661 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1662 decode_enumerated_bitfield(ra_flags, ND_RA_FLAG_RTPREF_MASK, 8,
1663 names_router_pref, "Router preference: %s"));
1665 /* Router lifetime */
1666 proto_tree_add_uint(icmp6_tree, hf_icmpv6_ra_router_lifetime, tvb,
1667 offset + offsetof(struct nd_router_advert, nd_ra_router_lifetime),
1668 2, (guint16)g_ntohs(ra->nd_ra_router_lifetime));
1670 /* Reachable time */
1671 proto_tree_add_uint(icmp6_tree, hf_icmpv6_ra_reachable_time, tvb,
1672 offset + offsetof(struct nd_router_advert, nd_ra_reachable), 4,
1673 pntohl(&ra->nd_ra_reachable));
1676 proto_tree_add_uint(icmp6_tree, hf_icmpv6_ra_retrans_timer, tvb,
1677 offset + offsetof(struct nd_router_advert, nd_ra_retransmit), 4,
1678 pntohl(&ra->nd_ra_retransmit));
1680 dissect_icmpv6ndopt(tvb, offset + sizeof(struct nd_router_advert), pinfo, icmp6_tree);
1683 case ND_NEIGHBOR_SOLICIT:
1685 struct nd_neighbor_solicit nd_neighbor_solicit, *ns;
1687 ns = &nd_neighbor_solicit;
1688 tvb_memcpy(tvb, (guint8 *)ns, offset, sizeof *ns);
1689 proto_tree_add_text(icmp6_tree, tvb,
1690 offset + offsetof(struct nd_neighbor_solicit, nd_ns_target), 16,
1693 get_hostname6(&ns->nd_ns_target),
1697 ip6_to_str(&ns->nd_ns_target));
1699 dissect_icmpv6ndopt(tvb, offset + sizeof(*ns), pinfo, icmp6_tree);
1702 case ND_NEIGHBOR_ADVERT:
1704 int flagoff, targetoff;
1706 struct e_in6_addr na_target;
1708 flagoff = offset + offsetof(struct nd_neighbor_advert, nd_na_flags_reserved);
1709 na_flags = tvb_get_ntohl(tvb, flagoff);
1711 tf = proto_tree_add_text(icmp6_tree, tvb, flagoff, 4, "Flags: 0x%08x", na_flags);
1712 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1713 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
1714 decode_boolean_bitfield(na_flags,
1715 ND_NA_FLAG_ROUTER, 32, "Router", "Not router"));
1716 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
1717 decode_boolean_bitfield(na_flags,
1718 ND_NA_FLAG_SOLICITED, 32, "Solicited", "Not adverted"));
1719 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
1720 decode_boolean_bitfield(na_flags,
1721 ND_NA_FLAG_OVERRIDE, 32, "Override", "Not override"));
1723 targetoff = offset + offsetof(struct nd_neighbor_advert, nd_na_target);
1724 tvb_memcpy(tvb, (guint8 *)&na_target, targetoff, sizeof na_target);
1725 proto_tree_add_text(icmp6_tree, tvb, targetoff, 16,
1728 get_hostname6(&na_target),
1732 ip6_to_str(&na_target));
1734 dissect_icmpv6ndopt(tvb, offset + sizeof(struct nd_neighbor_advert), pinfo, icmp6_tree);
1739 struct nd_redirect nd_redirect, *rd;
1742 tvb_memcpy(tvb, (guint8 *)rd, offset, sizeof *rd);
1743 proto_tree_add_text(icmp6_tree, tvb,
1744 offset + offsetof(struct nd_redirect, nd_rd_target), 16,
1747 get_hostname6(&rd->nd_rd_target),
1751 ip6_to_str(&rd->nd_rd_target));
1753 proto_tree_add_text(icmp6_tree, tvb,
1754 offset + offsetof(struct nd_redirect, nd_rd_dst), 16,
1756 "Destination: %s (%s)",
1757 get_hostname6(&rd->nd_rd_dst),
1761 ip6_to_str(&rd->nd_rd_dst));
1763 dissect_icmpv6ndopt(tvb, offset + sizeof(*rd), pinfo, icmp6_tree);
1766 case ICMP6_ROUTER_RENUMBERING:
1767 dissect_rrenum(tvb, offset, pinfo, icmp6_tree);
1769 case ICMP6_NI_QUERY:
1770 case ICMP6_NI_REPLY:
1771 ni = (struct icmp6_nodeinfo *)dp;
1772 proto_tree_add_text(icmp6_tree, tvb,
1773 offset + offsetof(struct icmp6_nodeinfo, ni_qtype),
1774 sizeof(ni->ni_qtype),
1775 "Query type: 0x%04x (%s)", pntohs(&ni->ni_qtype),
1776 val_to_str(pntohs(&ni->ni_qtype), names_nodeinfo_qtype,
1778 dissect_nodeinfo(tvb, offset, pinfo, icmp6_tree);
1780 case ICMP6_MIP6_DHAAD_REQUEST:
1781 proto_tree_add_text(icmp6_tree, tvb,
1782 offset + 4, 2, "Identifier: %d (0x%02x)",
1783 tvb_get_ntohs(tvb, offset + 4),
1784 tvb_get_ntohs(tvb, offset + 4));
1785 proto_tree_add_text(icmp6_tree, tvb,
1786 offset + 6, 2, "Reserved: %d",
1787 tvb_get_ntohs(tvb, offset + 6));
1789 case ICMP6_MIP6_DHAAD_REPLY:
1790 proto_tree_add_text(icmp6_tree, tvb,
1791 offset + 4, 2, "Identifier: %d (0x%02x)",
1792 tvb_get_ntohs(tvb, offset + 4),
1793 tvb_get_ntohs(tvb, offset + 4));
1794 proto_tree_add_text(icmp6_tree, tvb,
1795 offset + 6, 2, "Reserved: %d",
1796 tvb_get_ntohs(tvb, offset + 6));
1797 /* Show all Home Agent Addresses */
1800 int ha_num = (length - 8)/16;
1802 for (i = 0; i < ha_num; i++) {
1804 proto_tree_add_ipv6(icmp6_tree, hf_icmpv6_haad_ha_addrs,
1805 tvb, offset + 8 + suboffset, 16,
1806 tvb_get_ptr(tvb, offset + 8 + suboffset, 16));
1810 case ICMP6_MIP6_MPS:
1811 proto_tree_add_text(icmp6_tree, tvb,
1812 offset + 4, 2, "Identifier: %d (0x%02x)",
1813 tvb_get_ntohs(tvb, offset + 4),
1814 tvb_get_ntohs(tvb, offset + 4));
1815 proto_tree_add_text(icmp6_tree, tvb,
1816 offset + 6, 2, "Reserved: %d",
1817 tvb_get_ntohs(tvb, offset + 6));
1819 case ICMP6_MIP6_MPA:
1820 proto_tree_add_text(icmp6_tree, tvb,
1821 offset + 4, 2, "Identifier: %d (0x%02x)",
1822 tvb_get_ntohs(tvb, offset + 4),
1823 tvb_get_ntohs(tvb, offset + 4));
1824 proto_tree_add_text(icmp6_tree, tvb,
1826 decode_boolean_bitfield(tvb_get_guint8(tvb, offset + 6),
1828 "Managed Address Configuration",
1829 "No Managed Address Configuration"));
1830 proto_tree_add_text(icmp6_tree, tvb,
1832 decode_boolean_bitfield(tvb_get_guint8(tvb, offset + 6),
1834 "Other Stateful Configuration",
1835 "No Other Stateful Configuration"));
1836 proto_tree_add_text(icmp6_tree, tvb,
1837 offset + 7, 1, "Reserved: %d",
1838 tvb_get_guint8(tvb, offset + 7));
1839 /* Show all options */
1840 dissect_icmpv6ndopt(tvb, offset + 8, pinfo, icmp6_tree);
1842 case ICMP6_EXPERIMENTAL_MOBILITY:
1843 switch (dp->icmp6_data8[0]) {
1844 case FMIP6_SUBTYPE_RTSOLPR:
1846 struct fmip6_rtsolpr *rtsolpr;
1847 rtsolpr = (struct fmip6_rtsolpr*) dp;
1848 proto_tree_add_text(icmp6_tree, tvb,
1850 "Subtype: Router Solicitation for Proxy Advertisement");
1851 proto_tree_add_text(icmp6_tree, tvb,
1853 "Identifier: %d", pntohs(&rtsolpr->fmip6_rtsolpr_id));
1854 dissect_icmpv6fmip6opt(tvb, offset + sizeof(*dp), icmp6_tree);
1857 case FMIP6_SUBTYPE_PRRTADV:
1859 struct fmip6_prrtadv *prrtadv;
1860 prrtadv = (struct fmip6_prrtadv*) dp;
1861 proto_tree_add_text(icmp6_tree, tvb,
1863 "Subtype: Proxy Router Advertisement");
1864 proto_tree_add_text(icmp6_tree, tvb,
1866 "Identifier: %d", pntohs(&prrtadv->fmip6_prrtadv_id));
1867 dissect_icmpv6fmip6opt(tvb, offset + sizeof(*dp), icmp6_tree);
1870 case FMIP6_SUBTYPE_HI:
1872 struct fmip6_hi *hi;
1875 hi = (struct fmip6_hi*) dp;
1876 proto_tree_add_text(icmp6_tree, tvb,
1878 "Subtype: Handover Initiate");
1880 flagoff = offset + offsetof(struct fmip6_hi, fmip6_hi_flags_reserved);
1881 hi_flags = tvb_get_guint8(tvb, flagoff);
1882 tf = proto_tree_add_text(icmp6_tree, tvb, flagoff, 1, "Flags: 0x%02x", hi_flags);
1883 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1884 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1885 decode_boolean_bitfield(hi_flags,
1886 FMIP_HI_FLAG_ASSIGNED, 8, "Assigned", "Not assigned"));
1887 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1888 decode_boolean_bitfield(hi_flags,
1889 FMIP_HI_FLAG_BUFFER, 8, "Buffered", "Not buffered"));
1890 proto_tree_add_text(icmp6_tree, tvb,
1892 "Identifier: %d", pntohs(&hi->fmip6_hi_id));
1893 dissect_icmpv6fmip6opt(tvb, offset + sizeof(*dp), icmp6_tree);
1896 case FMIP6_SUBTYPE_HACK:
1898 struct fmip6_hack *hack;
1899 hack = (struct fmip6_hack*) dp;
1900 proto_tree_add_text(icmp6_tree, tvb,
1902 "Subtype: Handover Acknowledge");
1903 proto_tree_add_text(icmp6_tree, tvb,
1905 "Identifier: %d", pntohs(&hack->fmip6_hack_id));
1906 dissect_icmpv6fmip6opt(tvb, offset + sizeof(*dp), icmp6_tree);
1912 next_tvb = tvb_new_subset(tvb, offset + sizeof(*dp), -1, -1);
1913 call_dissector(data_handle,next_tvb, pinfo, tree);
1920 proto_register_icmpv6(void)
1922 static hf_register_info hf[] = {
1924 { "Type", "icmpv6.type", FT_UINT8, BASE_DEC, NULL, 0x0,
1927 { "Code", "icmpv6.code", FT_UINT8, BASE_DEC, NULL, 0x0,
1929 { &hf_icmpv6_checksum,
1930 { "Checksum", "icmpv6.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
1932 { &hf_icmpv6_checksum_bad,
1933 { "Bad Checksum", "icmpv6.checksum_bad", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1935 { &hf_icmpv6_haad_ha_addrs,
1936 { "Home Agent Addresses", "icmpv6.haad.ha_addrs",
1937 FT_IPv6, BASE_HEX, NULL, 0x0,
1939 { &hf_icmpv6_ra_cur_hop_limit,
1940 { "Cur hop limit", "icmpv6.ra.cur_hop_limit", FT_UINT8, BASE_DEC, NULL, 0x0,
1941 "Current hop limit", HFILL }},
1942 { &hf_icmpv6_ra_router_lifetime,
1943 { "Router lifetime", "icmpv6.ra.router_lifetime", FT_UINT16, BASE_DEC, NULL, 0x0,
1944 "Router lifetime (s)", HFILL }},
1945 { &hf_icmpv6_ra_reachable_time,
1946 { "Reachable time", "icmpv6.ra.reachable_time", FT_UINT32, BASE_DEC, NULL, 0x0,
1947 "Reachable time (ms)", HFILL }},
1948 { &hf_icmpv6_ra_retrans_timer,
1949 { "Retrans timer", "icmpv6.ra.retrans_timer", FT_UINT32, BASE_DEC, NULL, 0x0,
1950 "Retrans timer (ms)", HFILL }},
1951 { &hf_icmpv6_option,
1952 { "ICMPv6 Option", "icmpv6.option", FT_NONE, BASE_NONE, NULL, 0x0,
1954 { &hf_icmpv6_option_type,
1955 { "Type", "icmpv6.option.type", FT_UINT8, BASE_DEC, VALS(option_vals), 0x0,
1956 "Options type", HFILL }},
1957 { &hf_icmpv6_option_length,
1958 { "Length", "icmpv6.option.length", FT_UINT8, BASE_DEC, NULL, 0x0,
1959 "Options length (in bytes)", HFILL }},
1961 static gint *ett[] = {
1966 &ett_nodeinfo_subject4,
1967 &ett_nodeinfo_subject6,
1968 &ett_nodeinfo_node4,
1969 &ett_nodeinfo_node6,
1970 &ett_nodeinfo_nodebitmap,
1971 &ett_nodeinfo_nodedns,
1975 proto_icmpv6 = proto_register_protocol("Internet Control Message Protocol v6",
1976 "ICMPv6", "icmpv6");
1977 proto_register_field_array(proto_icmpv6, hf, array_length(hf));
1978 proto_register_subtree_array(ett, array_length(ett));
1982 proto_reg_handoff_icmpv6(void)
1984 dissector_handle_t icmpv6_handle;
1986 icmpv6_handle = create_dissector_handle(dissect_icmpv6, proto_icmpv6);
1987 dissector_add("ip.proto", IP_PROTO_ICMPV6, icmpv6_handle);
1990 * Get a handle for the IPv6 dissector.
1992 ipv6_handle = find_dissector("ipv6");
1993 data_handle = find_dissector("data");