proto_tree_add_subtree[_format]
[metze/wireshark/wip.git] / epan / dissectors / packet-icmp.c
1 /* packet-icmp.c
2  * Routines for ICMP - Internet Control Message Protocol
3  *
4  * Wireshark - Network traffic analyzer
5  * By Gerald Combs <gerald@wireshark.org>
6  * Copyright 1998 Gerald Combs
7  *
8  * Monday, June 27, 2005
9  * Support for the ICMP extensions for MPLS
10  * (http://www.ietf.org/proceedings/01aug/I-D/draft-ietf-mpls-icmp-02.txt
11  *  which has been replaced by rfcs 4884 and 4950)
12  * by   Maria-Luiza Crivat <luizacri@gmail.com>
13  * &    Brice Augustin <bricecotte@gmail.com>
14  *
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License
17  * as published by the Free Software Foundation; either version 2
18  * of the License, or (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28  *
29  * Added support for ICMP extensions RFC 4884 and RFC 5837
30  * (c) 2011 Gaurav Tungatkar <gstungat@ncsu.edu>
31  */
32
33 #include "config.h"
34
35 #include <stdlib.h>
36
37 #include <glib.h>
38 #include <time.h>
39
40 #include <epan/packet.h>
41 #include <epan/ipproto.h>
42 #include <epan/prefs.h>
43 #include <epan/expert.h>
44 #include <epan/in_cksum.h>
45 #include <epan/to_str.h>
46
47 #include "packet-ip.h"
48 #include "packet-icmp.h"
49 #include <epan/conversation.h>
50 #include <epan/wmem/wmem.h>
51 #include <epan/tap.h>
52
53 void proto_register_icmp(void);
54 void proto_reg_handoff_icmp(void);
55
56 static int icmp_tap = -1;
57
58 /* Conversation related data */
59 static int hf_icmp_resp_in = -1;
60 static int hf_icmp_resp_to = -1;
61 static int hf_icmp_no_resp = -1;
62 static int hf_icmp_resptime = -1;
63 static int hf_icmp_data_time = -1;
64 static int hf_icmp_data_time_relative = -1;
65
66 typedef struct _icmp_conv_info_t {
67         wmem_tree_t *unmatched_pdus;
68         wmem_tree_t *matched_pdus;
69 } icmp_conv_info_t;
70
71 static icmp_transaction_t *transaction_start(packet_info * pinfo,
72                                              proto_tree * tree,
73                                              guint32 * key);
74 static icmp_transaction_t *transaction_end(packet_info * pinfo,
75                                            proto_tree * tree,
76                                            guint32 * key);
77
78 /* Decode the end of the ICMP payload as ICMP MPLS extensions
79 if the packet in the payload has more than 128 bytes */
80 static gboolean favor_icmp_mpls_ext = FALSE;
81
82 int proto_icmp = -1;
83 static int hf_icmp_type = -1;
84 static int hf_icmp_code = -1;
85 static int hf_icmp_checksum = -1;
86 static int hf_icmp_checksum_bad = -1;
87 static int hf_icmp_ident = -1;
88 static int hf_icmp_ident_le = -1;
89 static int hf_icmp_seq_num = -1;
90 static int hf_icmp_seq_num_le = -1;
91 static int hf_icmp_mtu = -1;
92 static int hf_icmp_redir_gw = -1;
93 static int hf_icmp_length = -1;
94
95 /* Mobile ip */
96 static int hf_icmp_mip_type = -1;
97 static int hf_icmp_mip_length = -1;
98 static int hf_icmp_mip_prefix_length = -1;
99 static int hf_icmp_mip_seq = -1;
100 static int hf_icmp_mip_life = -1;
101 static int hf_icmp_mip_flags = -1;
102 static int hf_icmp_mip_r = -1;
103 static int hf_icmp_mip_b = -1;
104 static int hf_icmp_mip_h = -1;
105 static int hf_icmp_mip_f = -1;
106 static int hf_icmp_mip_m = -1;
107 static int hf_icmp_mip_g = -1;
108 static int hf_icmp_mip_v = -1;
109 static int hf_icmp_mip_rt = -1;
110 static int hf_icmp_mip_u = -1;
111 static int hf_icmp_mip_x = -1;
112 static int hf_icmp_mip_reserved = -1;
113 static int hf_icmp_mip_coa = -1;
114 static int hf_icmp_mip_challenge = -1;
115
116 /* extensions RFC 4884*/
117 static int hf_icmp_ext = -1;
118 static int hf_icmp_ext_version = -1;
119 static int hf_icmp_ext_reserved = -1;
120 static int hf_icmp_ext_checksum = -1;
121 static int hf_icmp_ext_checksum_bad = -1;
122 static int hf_icmp_ext_length = -1;
123 static int hf_icmp_ext_class = -1;
124 static int hf_icmp_ext_c_type = -1;
125
126 /* Interface information extension RFC 5837 */
127 static int hf_icmp_int_info_ifindex = -1;
128 static int hf_icmp_int_info_ipaddr = -1;
129 static int hf_icmp_int_info_name = -1;
130 static int hf_icmp_int_info_mtu = -1;
131 static int hf_icmp_int_info_afi = -1;
132 static int hf_icmp_int_info_ipv4 = -1;
133 static int hf_icmp_int_info_ipv6 = -1;
134 static int hf_icmp_int_info_role = -1;
135 static int hf_icmp_int_info_reserved = -1;
136 static gint ett_icmp_interface_info_object = -1;
137 static gint ett_icmp_interface_ipaddr = -1;
138 static gint ett_icmp_interface_name = -1;
139 /* MPLS extension object*/
140 static int hf_icmp_mpls_label = -1;
141 static int hf_icmp_mpls_exp = -1;
142 static int hf_icmp_mpls_s = -1;
143 static int hf_icmp_mpls_ttl = -1;
144
145 static gint ett_icmp = -1;
146 static gint ett_icmp_mip = -1;
147 static gint ett_icmp_mip_flags = -1;
148
149 /* extensions */
150 static gint ett_icmp_ext = -1;
151 static gint ett_icmp_ext_object = -1;
152
153 /* MPLS extensions */
154 static gint ett_icmp_mpls_stack_object = -1;
155
156 static expert_field ei_icmp_resp_not_found = EI_INIT;
157
158
159 /* ICMP definitions */
160 #define ICMP_ECHOREPLY     0
161 #define ICMP_UNREACH       3
162 #define ICMP_SOURCEQUENCH  4
163 #define ICMP_REDIRECT      5
164 #define ICMP_ALTHOST       6
165 #define ICMP_ECHO          8
166 #define ICMP_RTRADVERT     9
167 #define ICMP_RTRSOLICIT   10
168 #define ICMP_TIMXCEED     11
169 #define ICMP_PARAMPROB    12
170 #define ICMP_TSTAMP       13
171 #define ICMP_TSTAMPREPLY  14
172 #define ICMP_IREQ         15
173 #define ICMP_IREQREPLY    16
174 #define ICMP_MASKREQ      17
175 #define ICMP_MASKREPLY    18
176 #define ICMP_PHOTURIS     40
177
178 /* ICMP UNREACHABLE */
179 #define ICMP_NET_UNREACH        0       /* Network Unreachable */
180 #define ICMP_HOST_UNREACH       1       /* Host Unreachable */
181 #define ICMP_PROT_UNREACH       2       /* Protocol Unreachable */
182 #define ICMP_PORT_UNREACH       3       /* Port Unreachable */
183 #define ICMP_FRAG_NEEDED        4       /* Fragmentation Needed/DF set */
184 #define ICMP_SR_FAILED          5       /* Source Route failed */
185 #define ICMP_NET_UNKNOWN        6
186 #define ICMP_HOST_UNKNOWN       7
187 #define ICMP_HOST_ISOLATED      8
188 #define ICMP_NET_ANO            9
189 #define ICMP_HOST_ANO           10
190 #define ICMP_NET_UNR_TOS        11
191 #define ICMP_HOST_UNR_TOS       12
192 #define ICMP_PKT_FILTERED       13      /* Packet filtered */
193 #define ICMP_PREC_VIOLATION     14      /* Precedence violation */
194 #define ICMP_PREC_CUTOFF        15      /* Precedence cut off */
195
196 #define ICMP_MIP_EXTENSION_PAD  0
197 #define ICMP_MIP_MOB_AGENT_ADV  16
198 #define ICMP_MIP_PREFIX_LENGTHS 19
199 #define ICMP_MIP_CHALLENGE      24
200
201 static dissector_handle_t ip_handle;
202 static dissector_handle_t data_handle;
203
204 static const value_string icmp_type_str[] = {
205         {ICMP_ECHOREPLY, "Echo (ping) reply"},
206         {1, "Reserved"},
207         {2, "Reserved"},
208         {ICMP_UNREACH, "Destination unreachable"},
209         {ICMP_SOURCEQUENCH, "Source quench (flow control)"},
210         {ICMP_REDIRECT, "Redirect"},
211         {ICMP_ALTHOST, "Alternate host address"},
212         {ICMP_ECHO, "Echo (ping) request"},
213         {ICMP_RTRADVERT, "Router advertisement"},
214         {ICMP_RTRSOLICIT, "Router solicitation"},
215         {ICMP_TIMXCEED, "Time-to-live exceeded"},
216         {ICMP_PARAMPROB, "Parameter problem"},
217         {ICMP_TSTAMP, "Timestamp request"},
218         {ICMP_TSTAMPREPLY, "Timestamp reply"},
219         {ICMP_IREQ, "Information request"},
220         {ICMP_IREQREPLY, "Information reply"},
221         {ICMP_MASKREQ, "Address mask request"},
222         {ICMP_MASKREPLY, "Address mask reply"},
223         {19, "Reserved (for security)"},
224         {30, "Traceroute"},
225         {31, "Datagram Conversion Error"},
226         {32, "Mobile Host Redirect"},
227         {33, "IPv6 Where-Are-You"},
228         {34, "IPv6 I-Am-Here"},
229         {35, "Mobile Registration Request"},
230         {36, "Mobile Registration Reply"},
231         {37, "Domain Name Request"},
232         {38, "Domain Name Reply"},
233         {39, "SKIP"},
234         {ICMP_PHOTURIS, "Photuris"},
235         {41, "Experimental mobility protocols"},
236         {0, NULL}
237 };
238
239 static const value_string unreach_code_str[] = {
240         {ICMP_NET_UNREACH, "Network unreachable"},
241         {ICMP_HOST_UNREACH, "Host unreachable"},
242         {ICMP_PROT_UNREACH, "Protocol unreachable"},
243         {ICMP_PORT_UNREACH, "Port unreachable"},
244         {ICMP_FRAG_NEEDED, "Fragmentation needed"},
245         {ICMP_SR_FAILED, "Source route failed"},
246         {ICMP_NET_UNKNOWN, "Destination network unknown"},
247         {ICMP_HOST_UNKNOWN, "Destination host unknown"},
248         {ICMP_HOST_ISOLATED, "Source host isolated"},
249         {ICMP_NET_ANO, "Network administratively prohibited"},
250         {ICMP_HOST_ANO, "Host administratively prohibited"},
251         {ICMP_NET_UNR_TOS, "Network unreachable for TOS"},
252         {ICMP_HOST_UNR_TOS, "Host unreachable for TOS"},
253         {ICMP_PKT_FILTERED, "Communication administratively filtered"},
254         {ICMP_PREC_VIOLATION, "Host precedence violation"},
255         {ICMP_PREC_CUTOFF, "Precedence cutoff in effect"},
256         {0, NULL}
257 };
258
259 static const value_string redir_code_str[] = {
260         {0, "Redirect for network"},
261         {1, "Redirect for host"},
262         {2, "Redirect for TOS and network"},
263         {3, "Redirect for TOS and host"},
264         {0, NULL}
265 };
266
267 static const value_string alt_host_code_str[] = {
268         {0, "Alternate address for host"},
269         {0, NULL}
270 };
271
272 static const value_string rtradvert_code_str[] = {
273         {0, "Normal router advertisement"},
274         {16, "Does not route common traffic"},
275         {0, NULL}
276 };
277
278 static const value_string ttl_code_str[] = {
279         {0, "Time to live exceeded in transit"},
280         {1, "Fragment reassembly time exceeded"},
281         {0, NULL}
282 };
283
284 static const value_string par_code_str[] = {
285         {0, "Pointer indicates the error"},
286         {1, "Required option missing"},
287         {2, "Bad length"},
288         {0, NULL}
289 };
290
291 static const value_string photuris_code_str[] = {
292         {0, "Bad SPI"},
293         {1, "Authentication Failed"},
294         {2, "Decompression Failed"},
295         {3, "Decryption Failed"},
296         {4, "Need Authentication"},
297         {5, "Need Authorization"},
298         {0, NULL}
299 };
300
301 static const value_string mip_extensions[] = {
302         {ICMP_MIP_EXTENSION_PAD, "One byte padding extension"}, /* RFC 2002 */
303         {ICMP_MIP_MOB_AGENT_ADV, "Mobility Agent Advertisement Extension"},
304         /* RFC 2002 */
305         {ICMP_MIP_PREFIX_LENGTHS, "Prefix Lengths Extension"},  /* RFC 2002 */
306         {ICMP_MIP_CHALLENGE, "Challenge Extension"},    /* RFC 3012 */
307         {0, NULL}
308 };
309
310 /* RFC 5837 ICMP extension - Interface Information Object
311  * Interface Role
312  */
313 static const value_string interface_role_str[] = {
314         {0, "IP interface upon which datagram arrived"},
315         {1,
316          "sub-IP component of an IP interface upon which datagram arrived"},
317         {2, "IP interface through which datagram would be forwarded"},
318         {3, "IP next-hop to which datagram would be forwarded"},
319         {0, NULL}
320 };
321
322 #define INT_INFO_INTERFACE_ROLE                 0xc0
323 #define INT_INFO_RESERVED                       0x30
324 #define INT_INFO_IFINDEX                        0x08
325 #define INT_INFO_IPADDR                         0x04
326 #define INT_INFO_NAME                           0x02
327 #define INT_INFO_MTU                            0x01
328
329 #define INTERFACE_INFORMATION_OBJECT_CLASS      2
330
331 #define MPLS_STACK_ENTRY_OBJECT_CLASS           1
332 #define MPLS_EXTENDED_PAYLOAD_OBJECT_CLASS      0
333
334 #define MPLS_STACK_ENTRY_C_TYPE                 1
335 #define MPLS_EXTENDED_PAYLOAD_C_TYPE            1
336
337 #define INET6_ADDRLEN                           16
338
339 static conversation_t *_find_or_create_conversation(packet_info * pinfo)
340 {
341         conversation_t *conv = NULL;
342
343         /* Have we seen this conversation before? */
344         conv =
345             find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
346                               pinfo->ptype, 0, 0, 0);
347         if (conv == NULL) {
348                 /* No, this is a new conversation. */
349                 conv =
350                     conversation_new(pinfo->fd->num, &pinfo->src,
351                                      &pinfo->dst, pinfo->ptype, 0, 0, 0);
352         }
353         return conv;
354 }
355
356 /*
357  * Dissect the mobile ip advertisement extensions.
358  */
359 static void
360 dissect_mip_extensions(tvbuff_t * tvb, int offset, proto_tree * tree)
361 {
362         guint8 type;
363         guint8 length;
364         guint16 flags;
365         proto_item *ti;
366         proto_tree *mip_tree = NULL;
367         proto_tree *flags_tree = NULL;
368         gint numCOAs;
369         gint i;
370
371         /* Not much to do if we're not parsing everything */
372         if (!tree)
373                 return;
374
375         while (tvb_reported_length_remaining(tvb, offset) > 0) {
376                 type = tvb_get_guint8(tvb, offset + 0);
377                 if (type) {
378                         length = tvb_get_guint8(tvb, offset + 1);
379                 } else {
380                         length = 0;
381                 }
382
383                 mip_tree = proto_tree_add_subtree_format(tree, tvb, offset,
384                                                                 1, ett_icmp_mip, &ti,
385                                                                 "Ext: %s", val_to_str(type,
386                                                                 mip_extensions,
387                                                                 "Unknown ext %u"));
388                 proto_tree_add_item(mip_tree, hf_icmp_mip_type,
389                                         tvb, offset, 1,
390                                         ENC_BIG_ENDIAN);
391                 offset++;
392                 if (type != ICMP_MIP_EXTENSION_PAD)
393                 {
394                         proto_item_set_len(ti, length + 2);
395
396                         /* length */
397                         proto_tree_add_item(mip_tree, hf_icmp_mip_length,
398                                                 tvb, offset, 1,
399                                                 ENC_BIG_ENDIAN);
400                         offset++;
401                 }
402
403                 switch (type) {
404                 case ICMP_MIP_EXTENSION_PAD:
405                         /* One byte padding extension */
406                         break;
407                 case ICMP_MIP_MOB_AGENT_ADV:
408                         /* Mobility Agent Advertisement Extension (RFC 2002) */
409                         /* Add our fields */
410                         /* sequence number */
411                         proto_tree_add_item(mip_tree, hf_icmp_mip_seq, tvb,
412                                             offset, 2, ENC_BIG_ENDIAN);
413                         offset += 2;
414                         /* Registration Lifetime */
415                         proto_tree_add_item(mip_tree, hf_icmp_mip_life,
416                                             tvb, offset, 2,
417                                             ENC_BIG_ENDIAN);
418                         offset += 2;
419                         /* flags */
420                         flags = tvb_get_ntohs(tvb, offset);
421                         ti = proto_tree_add_uint(mip_tree,
422                                                  hf_icmp_mip_flags, tvb,
423                                                  offset, 2, flags);
424                         flags_tree =
425                             proto_item_add_subtree(ti, ett_icmp_mip_flags);
426                         proto_tree_add_boolean(flags_tree, hf_icmp_mip_r,
427                                                tvb, offset, 2, flags);
428                         proto_tree_add_boolean(flags_tree, hf_icmp_mip_b,
429                                                tvb, offset, 2, flags);
430                         proto_tree_add_boolean(flags_tree, hf_icmp_mip_h,
431                                                tvb, offset, 2, flags);
432                         proto_tree_add_boolean(flags_tree, hf_icmp_mip_f,
433                                                tvb, offset, 2, flags);
434                         proto_tree_add_boolean(flags_tree, hf_icmp_mip_m,
435                                                tvb, offset, 2, flags);
436                         proto_tree_add_boolean(flags_tree, hf_icmp_mip_g,
437                                                tvb, offset, 2, flags);
438                         proto_tree_add_boolean(flags_tree, hf_icmp_mip_v,
439                                                tvb, offset, 2, flags);
440                         proto_tree_add_boolean(flags_tree, hf_icmp_mip_rt,
441                                                tvb, offset, 2, flags);
442                         proto_tree_add_boolean(flags_tree, hf_icmp_mip_u,
443                                                tvb, offset, 2, flags);
444                         proto_tree_add_boolean(flags_tree, hf_icmp_mip_x,
445                                                tvb, offset, 2, flags);
446
447                         /* Reserved */
448                         proto_tree_add_uint(flags_tree,
449                                             hf_icmp_mip_reserved, tvb,
450                                             offset, 2, flags);
451                         offset += 2;
452
453                         /* COAs */
454                         numCOAs = (length - 6) / 4;
455                         for (i = 0; i < numCOAs; i++) {
456                                 proto_tree_add_item(mip_tree,
457                                                     hf_icmp_mip_coa, tvb,
458                                                     offset, 4,
459                                                     ENC_BIG_ENDIAN);
460                                 offset += 4;
461                         }
462                         break;
463                 case ICMP_MIP_PREFIX_LENGTHS:
464                         /* Prefix-Lengths Extension  (RFC 2002) */
465                         /* Add our fields */
466
467                         /* prefix lengths */
468                         for (i = 0; i < length; i++) {
469                                 proto_tree_add_item(mip_tree,
470                                                     hf_icmp_mip_prefix_length,
471                                                     tvb, offset, 1,
472                                                     ENC_BIG_ENDIAN);
473                                 offset++;
474                         }
475                         break;
476                 case ICMP_MIP_CHALLENGE:
477                         /* Challenge Extension  (RFC 3012) */
478                         /* challenge */
479                         proto_tree_add_item(mip_tree,
480                                             hf_icmp_mip_challenge, tvb,
481                                             offset, length, ENC_NA);
482                         offset += length;
483
484                         break;
485                 default:
486                         /* data, if any */
487                         if (length != 0) {
488                                 proto_tree_add_text(mip_tree, tvb, offset,
489                                                     length, "Contents");
490                                 offset += length;
491                         }
492
493                         break;
494                 }
495         }
496
497 }                               /* dissect_mip_extensions */
498
499 static gboolean
500 dissect_mpls_extended_payload_object(tvbuff_t * tvb, gint offset,
501                                      proto_tree * ext_object_tree,
502                                      proto_item * tf_object)
503 {
504
505         guint16 obj_length, obj_trunc_length;
506         gboolean unknown_object;
507         guint8 c_type;
508         unknown_object = FALSE;
509         /* Object length */
510         obj_length = tvb_get_ntohs(tvb, offset);
511
512         obj_trunc_length =
513             MIN(obj_length, tvb_reported_length_remaining(tvb, offset));
514
515         /* C-Type */
516         c_type = tvb_get_guint8(tvb, offset + 3);
517         proto_tree_add_uint(ext_object_tree, hf_icmp_ext_c_type, tvb,
518                             offset + 3, 1, c_type);
519
520         /* skip the object header */
521         offset += 4;
522
523         switch (c_type) {
524         case MPLS_EXTENDED_PAYLOAD_C_TYPE:
525                 proto_item_set_text(tf_object, "Extended Payload");
526
527                 /* This object contains some portion of the original packet
528                    that could not fit in the 128 bytes of the ICMP payload */
529                 if (obj_trunc_length > 4) {
530                         proto_tree_add_text(ext_object_tree, tvb,
531                                             offset, obj_trunc_length - 4,
532                                             "Data (%d bytes)",
533                                             obj_trunc_length - 4);
534                 }
535                 break;
536         default:
537                 unknown_object = TRUE;
538         }                       /* end switch c_type */
539         return unknown_object;
540 }
541
542 static gboolean
543 dissect_mpls_stack_entry_object(tvbuff_t * tvb, gint offset,
544                                 proto_tree * ext_object_tree,
545                                 proto_item * tf_object)
546 {
547
548         proto_item *tf_entry;
549         proto_tree *mpls_stack_object_tree;
550         guint16 obj_length, obj_trunc_length;
551         gint obj_end_offset;
552         guint label;
553         guint8 ttl;
554         guint8 tmp;
555         gboolean unknown_object;
556         guint8 c_type;
557         unknown_object = FALSE;
558         /* Object length */
559         obj_length = tvb_get_ntohs(tvb, offset);
560
561         obj_trunc_length =
562             MIN(obj_length, tvb_reported_length_remaining(tvb, offset));
563         obj_end_offset = offset + obj_trunc_length;
564         /* C-Type */
565         c_type = tvb_get_guint8(tvb, offset + 3);
566         proto_tree_add_uint(ext_object_tree, hf_icmp_ext_c_type, tvb,
567                             offset + 3, 1, c_type);
568
569         /* skip the object header */
570         offset += 4;
571
572         switch (c_type) {
573         case MPLS_STACK_ENTRY_C_TYPE:
574                 proto_item_set_text(tf_object, "MPLS Stack Entry");
575                 /* For each entry */
576                 while (offset + 4 <= obj_end_offset) {
577                         if (tvb_reported_length_remaining(tvb, offset) < 4) {
578                                 /* Not enough room in the packet ! */
579                                 break;
580                         }
581                         /* Create a subtree for each entry (the text will be set later) */
582                         mpls_stack_object_tree = proto_tree_add_subtree(ext_object_tree,
583                                                                 tvb, offset, 4,
584                                                                 ett_icmp_mpls_stack_object, &tf_entry, " ");
585
586                         /* Label */
587                         label = (guint) tvb_get_ntohs(tvb, offset);
588                         tmp = tvb_get_guint8(tvb, offset + 2);
589                         label = (label << 4) + (tmp >> 4);
590
591                         proto_tree_add_uint(mpls_stack_object_tree,
592                                             hf_icmp_mpls_label, tvb,
593                                             offset, 3, label << 4);
594
595                         proto_item_set_text(tf_entry, "Label: %u", label);
596
597                         /* Experimental field (also called "CoS") */
598                         proto_tree_add_uint(mpls_stack_object_tree,
599                                             hf_icmp_mpls_exp, tvb,
600                                             offset + 2, 1, tmp);
601
602                         proto_item_append_text(tf_entry, ", Exp: %u",
603                                                (tmp >> 1) & 0x07);
604
605                         /* Stack bit */
606                         proto_tree_add_boolean(mpls_stack_object_tree,
607                                                hf_icmp_mpls_s, tvb,
608                                                offset + 2, 1, tmp);
609
610                         proto_item_append_text(tf_entry, ", S: %u",
611                                                tmp & 0x01);
612
613                         /* TTL */
614                         ttl = tvb_get_guint8(tvb, offset + 3);
615
616                         proto_tree_add_item(mpls_stack_object_tree,
617                                             hf_icmp_mpls_ttl, tvb,
618                                             offset + 3, 1, ENC_BIG_ENDIAN);
619
620                         proto_item_append_text(tf_entry, ", TTL: %u", ttl);
621
622                         /* Skip the entry */
623                         offset += 4;
624                 }
625
626                 if (offset < obj_end_offset) {
627                         proto_tree_add_text(ext_object_tree, tvb, offset,
628                                             obj_end_offset - offset,
629                                             "%d junk bytes",
630                                             obj_end_offset - offset);
631                 }
632                 break;
633
634         default:
635
636                 unknown_object = TRUE;
637
638                 break;
639         }                       /* end switch c_type */
640         return unknown_object;
641
642 }                               /* end dissect_mpls_stack_entry_object */
643
644 /* Dissect Interface Information Object RFC 5837*/
645 static gboolean
646 dissect_interface_information_object(tvbuff_t * tvb, gint offset,
647                                      proto_tree * ext_object_tree,
648                                      proto_item * tf_object)
649 {
650         proto_tree *int_name_object_tree = NULL;
651         proto_tree *int_ipaddr_object_tree;
652         guint16 obj_length, obj_trunc_length;
653         gint obj_end_offset;
654         guint8 c_type;
655         gboolean unknown_object;
656         guint8 if_index_flag;
657         guint8 ipaddr_flag;
658         guint8 name_flag;
659         guint32 if_index;
660         guint16 afi;
661         struct e_in6_addr ipaddr_v6;
662         guint8 int_name_length = 0;
663
664         unknown_object = FALSE;
665         /* Object length */
666         obj_length = tvb_get_ntohs(tvb, offset);
667
668         obj_trunc_length =
669             MIN(obj_length, tvb_reported_length_remaining(tvb, offset));
670         obj_end_offset = offset + obj_trunc_length;
671
672         /* C-Type */
673         c_type = tvb_get_guint8(tvb, offset + 3);
674
675         proto_item_set_text(tf_object, "Interface Information Object");
676         if (tvb_reported_length_remaining(tvb, offset) < 4) {
677                 /* Not enough room in the packet ! return unknown_object = TRUE */
678                 return TRUE;
679         }
680
681         if_index_flag = (c_type & INT_INFO_IFINDEX) >> 3;
682         ipaddr_flag = (c_type & INT_INFO_IPADDR) >> 2;
683         name_flag = (c_type & INT_INFO_NAME) >> 1;
684
685         {
686                 static const gint *c_type_fields[] = {
687                         &hf_icmp_int_info_role,
688                         &hf_icmp_int_info_reserved,
689                         &hf_icmp_int_info_ifindex,
690                         &hf_icmp_int_info_ipaddr,
691                         &hf_icmp_int_info_name,
692                         &hf_icmp_int_info_mtu,
693                         NULL
694                 };
695                 proto_tree_add_bitmask(ext_object_tree, tvb, offset + 3,
696                                        hf_icmp_ext_c_type,
697                                        ett_icmp_interface_info_object,
698                                        c_type_fields, ENC_BIG_ENDIAN);
699         }
700
701         /* skip header */
702         offset += 4;
703
704         /*if ifIndex is set, next 32 bits are ifIndex */
705         if (if_index_flag) {
706                 if (obj_end_offset >= offset + 4) {
707                         if_index = tvb_get_ntohl(tvb, offset);
708                         proto_tree_add_text(ext_object_tree,
709                                             tvb, offset, 4,
710                                             "Interface Index: %u",
711                                             if_index);
712                         offset += 4;
713                 } else {
714                         proto_tree_add_text(ext_object_tree,
715                                             tvb, offset, 4,
716                                             "Interface Index:(truncated)");
717                         return FALSE;
718                 }
719         }
720
721         /* IP Address Sub Object */
722         if (ipaddr_flag && (obj_end_offset >= offset + 2)) {
723                 /* Address Family Identifier */
724                 afi = tvb_get_ntohs(tvb, offset);
725
726                 /*
727                  * if afi = 1, IPv4 address, 2 bytes afi, 2 bytes rsvd, 4 bytes IP addr
728                  * if afi = 2, IPv6 address, 2 bytes afi, 2 bytes rsvd, 6 bytes IP addr
729                  */
730                 int_ipaddr_object_tree = proto_tree_add_subtree(ext_object_tree, tvb, offset,
731                                          afi == 1 ? 8 : 10, ett_icmp_interface_ipaddr, NULL,
732                                          "IP Address Sub-Object");
733
734                 proto_tree_add_uint(int_ipaddr_object_tree,
735                                     hf_icmp_int_info_afi, tvb, offset, 2,
736                                     afi);
737
738                 /* skip reserved */
739                 offset += 4;
740                 if (afi == 1 && (obj_end_offset >= offset + 4)) {
741                         proto_tree_add_ipv4(int_ipaddr_object_tree,
742                                             hf_icmp_int_info_ipv4, tvb,
743                                             offset, 4, tvb_get_ntohl(tvb,
744                                                                      offset));
745                         offset += 4;
746                 } else if (afi == 2
747                            && (obj_end_offset >= offset + INET6_ADDRLEN)) {
748                         tvb_get_ipv6(tvb, offset, &ipaddr_v6);
749                         proto_tree_add_ipv6(int_ipaddr_object_tree,
750                                             hf_icmp_int_info_ipv6, tvb,
751                                             offset, INET6_ADDRLEN,
752                                             (guint8 *) & ipaddr_v6);
753                         offset += INET6_ADDRLEN;
754                 } else {
755                         proto_tree_add_text(int_ipaddr_object_tree, tvb,
756                                             offset,
757                                             offset - obj_end_offset,
758                                             "Bad IP Address");
759                         return FALSE;
760                 }
761         }
762
763         /* Interface Name Sub Object */
764         if (name_flag) {
765                 if (obj_end_offset >= offset + 1) {
766                         int_name_length = tvb_get_guint8(tvb, offset);
767                         int_name_object_tree = proto_tree_add_subtree(ext_object_tree, tvb,
768                                                  offset, int_name_length, ett_icmp_interface_name, NULL,
769                                                  "Interface Name Sub-Object");
770
771                         proto_tree_add_text(int_name_object_tree, tvb,
772                                             offset, 1, "Length: %u",
773                                             int_name_length);
774                 }
775                 if (obj_end_offset >= offset + 1 + int_name_length) {
776
777                         proto_tree_add_text(int_name_object_tree, tvb,
778                                             offset + 1, int_name_length,
779                                             "Interface Name: %s",
780                                             tvb_format_text(tvb, offset + 1, int_name_length));
781                 }
782         }
783
784
785         return unknown_object;
786
787 }                               /*end dissect_interface_information_object */
788
789 static void
790 dissect_extensions(tvbuff_t * tvb, gint offset, proto_tree * tree)
791 {
792         guint8 version;
793         guint8 class_num;
794         guint8 c_type;
795         guint16 cksum, computed_cksum;
796         guint16 obj_length, obj_trunc_length;
797         proto_item *ti, *tf_object, *hidden_item;
798         proto_tree *ext_tree, *ext_object_tree;
799         gint obj_end_offset;
800         guint reported_length;
801         gboolean unknown_object;
802         guint8 int_info_obj_count;
803
804         if (!tree)
805                 return;
806
807         ext_tree = NULL;
808         int_info_obj_count = 0;
809
810         reported_length = tvb_reported_length_remaining(tvb, offset);
811
812         if (reported_length < 4 /* Common header */ ) {
813                 proto_tree_add_text(tree, tvb, offset,
814                                     reported_length,
815                                     "ICMP Multi-Part Extensions (truncated)");
816                 return;
817         }
818
819         /* Add a tree for multi-part extensions RFC 4884 */
820         ti = proto_tree_add_none_format(tree, hf_icmp_ext, tvb,
821                                         offset, reported_length,
822                                         "ICMP Multi-Part Extensions");
823
824         ext_tree = proto_item_add_subtree(ti, ett_icmp_ext);
825
826         /* Version */
827         version = hi_nibble(tvb_get_guint8(tvb, offset));
828         proto_tree_add_uint(ext_tree, hf_icmp_ext_version, tvb, offset, 1,
829                             version);
830
831         /* Reserved */
832         proto_tree_add_item(ext_tree, hf_icmp_ext_reserved,
833                                    tvb, offset, 2, ENC_BIG_ENDIAN);
834
835         /* Checksum */
836         cksum = tvb_get_ntohs(tvb, offset + 2);
837
838         computed_cksum =
839             ip_checksum(tvb_get_ptr(tvb, offset, reported_length),
840                         reported_length);
841
842         if (computed_cksum == 0) {
843                 proto_tree_add_uint_format_value(ext_tree, hf_icmp_ext_checksum,
844                                            tvb, offset + 2, 2, cksum,
845                                            "0x%04x [correct]",
846                                            cksum);
847                 hidden_item =
848                     proto_tree_add_boolean(ext_tree,
849                                            hf_icmp_ext_checksum_bad, tvb,
850                                            offset + 2, 2, FALSE);
851         } else {
852                 proto_tree_add_uint_format_value(ext_tree, hf_icmp_ext_checksum,
853                                            tvb, offset + 2, 2, cksum,
854                                            "0x%04x [incorrect, should be 0x%04x]",
855                                            cksum, in_cksum_shouldbe(cksum,
856                                                                     computed_cksum));
857                 hidden_item =
858                     proto_tree_add_boolean(ext_tree,
859                                            hf_icmp_ext_checksum_bad, tvb,
860                                            offset + 2, 2, TRUE);
861         }
862         PROTO_ITEM_SET_HIDDEN(hidden_item);
863
864         if (version != 1 && version != 2) {
865                 /* Unsupported version */
866                 proto_item_append_text(ti, " (unsupported version)");
867                 return;
868         }
869
870         /* Skip the common header */
871         offset += 4;
872
873         /* While there is enough room to read an object */
874         while (tvb_reported_length_remaining(tvb, offset) >=
875                4 /* Object header */ ) {
876                 /* Object length */
877                 obj_length = tvb_get_ntohs(tvb, offset);
878
879                 obj_trunc_length =
880                     MIN(obj_length,
881                         tvb_reported_length_remaining(tvb, offset));
882
883                 obj_end_offset = offset + obj_trunc_length;
884
885                 /* Add a subtree for this object (the text will be reset later) */
886                 ext_object_tree = proto_tree_add_subtree(ext_tree, tvb, offset,
887                                                 MAX(obj_trunc_length, 4),
888                                                 ett_icmp_ext_object, &tf_object, "Unknown object");
889
890                 proto_tree_add_uint(ext_object_tree, hf_icmp_ext_length,
891                                     tvb, offset, 2, obj_length);
892
893                 /* Class */
894                 class_num = tvb_get_guint8(tvb, offset + 2);
895                 proto_tree_add_uint(ext_object_tree, hf_icmp_ext_class,
896                                     tvb, offset + 2, 1, class_num);
897
898                 /* C-Type */
899                 c_type = tvb_get_guint8(tvb, offset + 3);
900
901                 if (obj_length < 4 /* Object header */ ) {
902                         /* Thanks doc/README.developer :)) */
903                         proto_item_set_text(tf_object,
904                                             "Object with bad length");
905                         break;
906                 }
907
908
909                 switch (class_num) {
910                 case MPLS_STACK_ENTRY_OBJECT_CLASS:
911                         unknown_object =
912                             dissect_mpls_stack_entry_object(tvb, offset,
913                                                             ext_object_tree,
914                                                             tf_object);
915                         break;
916                 case INTERFACE_INFORMATION_OBJECT_CLASS:
917                         unknown_object =
918                             dissect_interface_information_object(tvb,
919                                                                  offset,
920                                                                  ext_object_tree,
921                                                                  tf_object);
922                         int_info_obj_count++;
923                         if (int_info_obj_count > 4) {
924                                 proto_item_set_text(tf_object,
925                                                     "More than 4 Interface Information Objects");
926                         }
927                         break;
928                 case MPLS_EXTENDED_PAYLOAD_OBJECT_CLASS:
929                         unknown_object =
930                             dissect_mpls_extended_payload_object(tvb,
931                                                                  offset,
932                                                                  ext_object_tree,
933                                                                  tf_object);
934                         break;
935                 default:
936
937                         unknown_object = TRUE;
938
939                         break;
940                 }               /* end switch class_num */
941
942                 /* Skip the object header */
943                 offset += 4;
944
945                 /* The switches couldn't decode the object */
946                 if (unknown_object == TRUE) {
947                         proto_item_set_text(tf_object,
948                                             "Unknown object (%d/%d)",
949                                             class_num, c_type);
950
951                         if (obj_trunc_length > 4) {
952                                 proto_tree_add_text(ext_object_tree, tvb,
953                                                     offset,
954                                                     obj_trunc_length - 4,
955                                                     "Data (%d bytes)",
956                                                     obj_trunc_length - 4);
957                         }
958                 }
959
960                 /* */
961                 if (obj_trunc_length < obj_length) {
962                         proto_item_append_text(tf_object, " (truncated)");
963                 }
964
965                 /* Go to the end of the object */
966                 offset = obj_end_offset;
967
968         }
969 }
970
971 #include <stdio.h>
972 /* ======================================================================= */
973 static icmp_transaction_t *transaction_start(packet_info * pinfo,
974                                              proto_tree * tree,
975                                              guint32 * key)
976 {
977         conversation_t *conversation;
978         icmp_conv_info_t *icmp_info;
979         icmp_transaction_t *icmp_trans;
980         wmem_tree_key_t icmp_key[3];
981         proto_item *it;
982
983         /* Handle the conversation tracking */
984         conversation = _find_or_create_conversation(pinfo);
985         icmp_info = (icmp_conv_info_t *)conversation_get_proto_data(conversation, proto_icmp);
986         if (icmp_info == NULL) {
987                 icmp_info = wmem_new(wmem_file_scope(), icmp_conv_info_t);
988                 icmp_info->unmatched_pdus = wmem_tree_new(wmem_file_scope());
989                 icmp_info->matched_pdus   = wmem_tree_new(wmem_file_scope());
990                 conversation_add_proto_data(conversation, proto_icmp,
991                                             icmp_info);
992         }
993
994         if (!PINFO_FD_VISITED(pinfo)) {
995                 /* this is a new request, create a new transaction structure and map it to the
996                    unmatched table
997                  */
998                 icmp_key[0].length = 2;
999                 icmp_key[0].key = key;
1000                 icmp_key[1].length = 0;
1001                 icmp_key[1].key = NULL;
1002
1003                 icmp_trans = wmem_new(wmem_file_scope(), icmp_transaction_t);
1004                 icmp_trans->rqst_frame = PINFO_FD_NUM(pinfo);
1005                 icmp_trans->resp_frame = 0;
1006                 icmp_trans->rqst_time = pinfo->fd->abs_ts;
1007                 nstime_set_zero(&icmp_trans->resp_time);
1008                 wmem_tree_insert32_array(icmp_info->unmatched_pdus, icmp_key,
1009                                        (void *) icmp_trans);
1010         } else {
1011                 /* Already visited this frame */
1012                 guint32 frame_num = pinfo->fd->num;
1013
1014                 icmp_key[0].length = 2;
1015                 icmp_key[0].key = key;
1016                 icmp_key[1].length = 1;
1017                 icmp_key[1].key = &frame_num;
1018                 icmp_key[2].length = 0;
1019                 icmp_key[2].key = NULL;
1020
1021                 icmp_trans =
1022                     (icmp_transaction_t *)wmem_tree_lookup32_array(icmp_info->matched_pdus,
1023                                            icmp_key);
1024         }
1025         if (icmp_trans == NULL) {
1026                 if (PINFO_FD_VISITED(pinfo)) {
1027                         /* No response found - add field and expert info */
1028                         it = proto_tree_add_item(tree, hf_icmp_no_resp, NULL, 0, 0,
1029                                                  ENC_NA);
1030                         PROTO_ITEM_SET_GENERATED(it);
1031
1032                         col_append_fstr(pinfo->cinfo, COL_INFO, " (no response found!)");
1033
1034                         /* Expert info.  TODO: add to _icmp_transaction_t type and sequence number
1035                            so can report here (and in taps) */
1036                         expert_add_info_format(pinfo, it, &ei_icmp_resp_not_found,
1037                                                "No response seen to ICMP request in frame %u",
1038                                                pinfo->fd->num);
1039                 }
1040
1041                 return NULL;
1042         }
1043
1044         /* Print state tracking in the tree */
1045         if (icmp_trans->resp_frame) {
1046                 it = proto_tree_add_uint(tree, hf_icmp_resp_in, NULL, 0, 0,
1047                                          icmp_trans->resp_frame);
1048                 PROTO_ITEM_SET_GENERATED(it);
1049
1050                 col_append_fstr(pinfo->cinfo, COL_INFO, " (reply in %d)",
1051                                 icmp_trans->resp_frame);
1052         }
1053
1054         return icmp_trans;
1055
1056 }                               /* transaction_start() */
1057
1058 /* ======================================================================= */
1059 static icmp_transaction_t *transaction_end(packet_info * pinfo,
1060                                            proto_tree * tree,
1061                                            guint32 * key)
1062 {
1063         conversation_t *conversation;
1064         icmp_conv_info_t *icmp_info;
1065         icmp_transaction_t *icmp_trans;
1066         wmem_tree_key_t icmp_key[3];
1067         proto_item *it;
1068         nstime_t ns;
1069         double resp_time;
1070
1071         conversation =
1072             find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
1073                               pinfo->ptype, 0, 0, 0);
1074         if (conversation == NULL) {
1075                 return NULL;
1076         }
1077
1078         icmp_info = (icmp_conv_info_t *)conversation_get_proto_data(conversation, proto_icmp);
1079         if (icmp_info == NULL) {
1080                 return NULL;
1081         }
1082
1083         if (!PINFO_FD_VISITED(pinfo)) {
1084                 guint32 frame_num;
1085
1086                 icmp_key[0].length = 2;
1087                 icmp_key[0].key = key;
1088                 icmp_key[1].length = 0;
1089                 icmp_key[1].key = NULL;
1090                 icmp_trans =
1091                     (icmp_transaction_t *)wmem_tree_lookup32_array(icmp_info->unmatched_pdus,
1092                                            icmp_key);
1093                 if (icmp_trans == NULL) {
1094                         return NULL;
1095                 }
1096
1097                 /* we have already seen this response, or an identical one */
1098                 if (icmp_trans->resp_frame != 0) {
1099                         return NULL;
1100                 }
1101
1102                 icmp_trans->resp_frame = PINFO_FD_NUM(pinfo);
1103
1104                 /* we found a match. Add entries to the matched table for both request and reply frames
1105                  */
1106                 icmp_key[0].length = 2;
1107                 icmp_key[0].key = key;
1108                 icmp_key[1].length = 1;
1109                 icmp_key[1].key = &frame_num;
1110                 icmp_key[2].length = 0;
1111                 icmp_key[2].key = NULL;
1112
1113                 frame_num = icmp_trans->rqst_frame;
1114                 wmem_tree_insert32_array(icmp_info->matched_pdus, icmp_key,
1115                                        (void *) icmp_trans);
1116
1117                 frame_num = icmp_trans->resp_frame;
1118                 wmem_tree_insert32_array(icmp_info->matched_pdus, icmp_key,
1119                                        (void *) icmp_trans);
1120         } else {
1121                 /* Already visited this frame */
1122                 guint32 frame_num = pinfo->fd->num;
1123
1124                 icmp_key[0].length = 2;
1125                 icmp_key[0].key = key;
1126                 icmp_key[1].length = 1;
1127                 icmp_key[1].key = &frame_num;
1128                 icmp_key[2].length = 0;
1129                 icmp_key[2].key = NULL;
1130
1131                 icmp_trans =
1132                     (icmp_transaction_t *)wmem_tree_lookup32_array(icmp_info->matched_pdus,
1133                                            icmp_key);
1134
1135                 if (icmp_trans == NULL) {
1136                         return NULL;
1137                 }
1138         }
1139
1140
1141         it = proto_tree_add_uint(tree, hf_icmp_resp_to, NULL, 0, 0,
1142                                  icmp_trans->rqst_frame);
1143         PROTO_ITEM_SET_GENERATED(it);
1144
1145         nstime_delta(&ns, &pinfo->fd->abs_ts, &icmp_trans->rqst_time);
1146         icmp_trans->resp_time = ns;
1147         resp_time = nstime_to_msec(&ns);
1148         it = proto_tree_add_double_format_value(tree, hf_icmp_resptime,
1149                                                 NULL, 0, 0, resp_time,
1150                                                 "%.3f ms", resp_time);
1151         PROTO_ITEM_SET_GENERATED(it);
1152
1153         col_append_fstr(pinfo->cinfo, COL_INFO, " (request in %d)",
1154                         icmp_trans->rqst_frame);
1155
1156         return icmp_trans;
1157
1158 }                               /* transaction_end() */
1159
1160 #define MSPERDAY            86400000
1161
1162 /* ======================================================================= */
1163 static guint32
1164 get_best_guess_mstimeofday(tvbuff_t * tvb, gint offset, guint32 comp_ts)
1165 {
1166         guint32 be_ts, le_ts;
1167
1168         /* Account for the special case from RFC 792 as best we can by clearing
1169          * the msb.  Ref: [Page 16] of http://tools.ietf.org/html/rfc792:
1170
1171          If the time is not available in milliseconds or cannot be provided
1172          with respect to midnight UT then any time can be inserted in a
1173          timestamp provided the high order bit of the timestamp is also set
1174          to indicate this non-standard value.
1175          */
1176         be_ts = tvb_get_ntohl(tvb, offset) & 0x7fffffff;
1177         le_ts = tvb_get_letohl(tvb, offset) & 0x7fffffff;
1178
1179         if (be_ts < MSPERDAY && le_ts >= MSPERDAY) {
1180                 return be_ts;
1181         }
1182
1183         if (le_ts < MSPERDAY && be_ts >= MSPERDAY) {
1184                 return le_ts;
1185         }
1186
1187         if (be_ts < MSPERDAY && le_ts < MSPERDAY) {
1188                 guint32 saved_be_ts = be_ts;
1189                 guint32 saved_le_ts = le_ts;
1190
1191                 /* Is this a rollover to a new day, clocks not synchronized, different
1192                  * timezones between originate and receive/transmit, .. what??? */
1193                 if (be_ts < comp_ts && be_ts <= (MSPERDAY / 4)
1194                     && comp_ts >= (MSPERDAY - (MSPERDAY / 4)))
1195                         be_ts += MSPERDAY;      /* Assume a rollover to a new day */
1196                 if (le_ts < comp_ts && le_ts <= (MSPERDAY / 4)
1197                     && comp_ts >= (MSPERDAY - (MSPERDAY / 4)))
1198                         le_ts += MSPERDAY;      /* Assume a rollover to a new day */
1199                 if ((be_ts - comp_ts) < (le_ts - comp_ts))
1200                         return saved_be_ts;
1201                 return saved_le_ts;
1202         }
1203
1204         /* Both are bigger than MSPERDAY, but neither one's msb's are set.  This
1205          * is clearly invalid, but now what TODO?  For now, take the one closest to
1206          * the comparative timestamp, which is another way of saying, "let's
1207          * return a deterministic wild guess. */
1208         if ((be_ts - comp_ts) < (le_ts - comp_ts)) {
1209                 return be_ts;
1210         }
1211         return le_ts;
1212 }                               /* get_best_guess_mstimeofday() */
1213
1214 /*
1215  * RFC 792 for basic ICMP.
1216  * RFC 1191 for ICMP_FRAG_NEEDED (with MTU of next hop).
1217  * RFC 1256 for router discovery messages.
1218  * RFC 2002 and 3012 for Mobile IP stuff.
1219  */
1220 static int
1221 dissect_icmp(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, void* data)
1222 {
1223         proto_tree *icmp_tree = NULL;
1224         proto_item *ti;
1225         guint8 icmp_type;
1226         guint8 icmp_code;
1227         guint8 icmp_original_dgram_length;
1228         guint length, reported_length;
1229         guint16 cksum, computed_cksum;
1230         const gchar *type_str, *code_str;
1231         guint8 num_addrs = 0;
1232         guint8 addr_entry_size = 0;
1233         int i;
1234         gboolean save_in_error_pkt;
1235         tvbuff_t *next_tvb;
1236         proto_item *item;
1237         guint32 conv_key[2];
1238         icmp_transaction_t *trans = NULL;
1239         nstime_t ts, time_relative;
1240         ws_ip *iph = (ws_ip*)data;
1241
1242         col_set_str(pinfo->cinfo, COL_PROTOCOL, "ICMP");
1243         col_clear(pinfo->cinfo, COL_INFO);
1244
1245         /* To do: check for runts, errs, etc. */
1246         icmp_type = tvb_get_guint8(tvb, 0);
1247         icmp_code = tvb_get_guint8(tvb, 1);
1248         cksum = tvb_get_ntohs(tvb, 2);
1249         /*length of original datagram carried in the ICMP payload. In terms of 32 bit
1250          * words.*/
1251         icmp_original_dgram_length = tvb_get_guint8(tvb, 5);
1252
1253         type_str =
1254             val_to_str_const(icmp_type, icmp_type_str,
1255                              "Unknown ICMP (obsolete or malformed?)");
1256
1257         switch (icmp_type) {
1258         case ICMP_UNREACH:
1259                 code_str =
1260                     val_to_str(icmp_code, unreach_code_str,
1261                                "Unknown code: %u");
1262                 break;
1263         case ICMP_REDIRECT:
1264                 code_str =
1265                     val_to_str(icmp_code, redir_code_str,
1266                                "Unknown code: %u");
1267                 break;
1268         case ICMP_ALTHOST:
1269                 code_str =
1270                     val_to_str(icmp_code, alt_host_code_str,
1271                                "Unknown code: %u");
1272                 break;
1273         case ICMP_RTRADVERT:
1274                 switch (icmp_code) {
1275                 case 0: /* Mobile-Ip */
1276                 case 16:        /* Mobile-Ip */
1277                         type_str = "Mobile IP Advertisement";
1278                         break;
1279                 }               /* switch icmp_code */
1280                 code_str =
1281                     val_to_str(icmp_code, rtradvert_code_str,
1282                                "Unknown code: %u");
1283                 break;
1284         case ICMP_TIMXCEED:
1285                 code_str =
1286                     val_to_str(icmp_code, ttl_code_str,
1287                                "Unknown code: %u");
1288                 break;
1289         case ICMP_PARAMPROB:
1290                 code_str =
1291                     val_to_str(icmp_code, par_code_str,
1292                                "Unknown code: %u");
1293                 break;
1294         case ICMP_PHOTURIS:
1295                 code_str =
1296                     val_to_str(icmp_code, photuris_code_str,
1297                                "Unknown code: %u");
1298                 break;
1299         default:
1300                 code_str = NULL;
1301                 break;
1302         }
1303
1304         col_add_fstr(pinfo->cinfo, COL_INFO, "%-20s", type_str);
1305         if (code_str) {
1306                 col_append_fstr(pinfo->cinfo, COL_INFO, " (%s)", code_str);
1307         }
1308
1309         length = tvb_length(tvb);
1310         reported_length = tvb_reported_length(tvb);
1311
1312         ti = proto_tree_add_item(tree, proto_icmp, tvb, 0, length, ENC_NA);
1313         icmp_tree = proto_item_add_subtree(ti, ett_icmp);
1314
1315         ti = proto_tree_add_item(icmp_tree, hf_icmp_type, tvb, 0, 1,
1316                                  ENC_BIG_ENDIAN);
1317         proto_item_append_text(ti, " (%s)", type_str);
1318
1319         ti = proto_tree_add_item(icmp_tree, hf_icmp_code, tvb, 1, 1,
1320                                  ENC_BIG_ENDIAN);
1321         if (code_str) {
1322                 proto_item_append_text(ti, " (%s)", code_str);
1323         }
1324
1325         if (!pinfo->fragmented && length >= reported_length
1326             && !pinfo->flags.in_error_pkt) {
1327                 /* The packet isn't part of a fragmented datagram, isn't
1328                    truncated, and isn't the payload of an error packet, so we can checksum
1329                    it. */
1330
1331                 computed_cksum =
1332                     ip_checksum(tvb_get_ptr(tvb, 0, reported_length),
1333                                 reported_length);
1334                 if (computed_cksum == 0) {
1335                         proto_tree_add_uint_format_value(icmp_tree,
1336                                                    hf_icmp_checksum, tvb,
1337                                                    2, 2, cksum,
1338                                                    "0x%04x [correct]",
1339                                                    cksum);
1340                         item =
1341                             proto_tree_add_boolean(icmp_tree,
1342                                                    hf_icmp_checksum_bad,
1343                                                    tvb, 2, 2, FALSE);
1344                         PROTO_ITEM_SET_HIDDEN(item);
1345                 } else {
1346                         proto_tree_add_uint_format_value(icmp_tree,
1347                                                    hf_icmp_checksum, tvb,
1348                                                    2, 2, cksum,
1349                                                    "0x%04x [incorrect, should be 0x%04x]",
1350                                                    cksum,
1351                                                    in_cksum_shouldbe(cksum,
1352                                                                      computed_cksum));
1353                         item =
1354                             proto_tree_add_boolean(icmp_tree,
1355                                                    hf_icmp_checksum_bad,
1356                                                    tvb, 2, 2, TRUE);
1357                         PROTO_ITEM_SET_HIDDEN(item);
1358                 }
1359         } else {
1360                 proto_tree_add_uint(icmp_tree, hf_icmp_checksum, tvb, 2, 2,
1361                                     cksum);
1362         }
1363
1364         /* Decode the second 4 bytes of the packet. */
1365         switch (icmp_type) {
1366         case ICMP_ECHOREPLY:
1367         case ICMP_ECHO:
1368         case ICMP_TSTAMP:
1369         case ICMP_TSTAMPREPLY:
1370         case ICMP_IREQ:
1371         case ICMP_IREQREPLY:
1372         case ICMP_MASKREQ:
1373         case ICMP_MASKREPLY:
1374                 proto_tree_add_item(icmp_tree, hf_icmp_ident, tvb, 4, 2,
1375                                     ENC_BIG_ENDIAN);
1376                 proto_tree_add_item(icmp_tree, hf_icmp_ident_le, tvb, 4, 2,
1377                                     ENC_LITTLE_ENDIAN);
1378                 proto_tree_add_item(icmp_tree, hf_icmp_seq_num, tvb, 6, 2,
1379                                     ENC_BIG_ENDIAN);
1380                 proto_tree_add_item(icmp_tree, hf_icmp_seq_num_le, tvb, 6,
1381                                     2, ENC_LITTLE_ENDIAN);
1382                 col_append_fstr(pinfo->cinfo, COL_INFO,
1383                                 " id=0x%04x, seq=%u/%u, ttl=%u",
1384                                 tvb_get_ntohs(tvb, 4), tvb_get_ntohs(tvb,
1385                                                                      6),
1386                                 tvb_get_letohs(tvb, 6), (iph != NULL) ? iph->ip_ttl : 0);
1387                 break;
1388
1389         case ICMP_UNREACH:
1390
1391                 /* If icmp_original_dgram_length > 0, then this packet is compliant with RFC 4884 and
1392                  * interpret the 6th octet as length of the original datagram
1393                  */
1394                 if (icmp_original_dgram_length > 0) {
1395                         ti = proto_tree_add_item(icmp_tree, hf_icmp_length,
1396                                                  tvb, 5, 1,
1397                                                  ENC_BIG_ENDIAN);
1398                         proto_item_append_text(ti,
1399                                                "Length of original datagram: %u",
1400                                                icmp_original_dgram_length *
1401                                                4);
1402                 }
1403
1404
1405                 switch (icmp_code) {
1406                 case ICMP_FRAG_NEEDED:
1407                         proto_tree_add_item(icmp_tree, hf_icmp_mtu, tvb, 6,
1408                                             2, ENC_BIG_ENDIAN);
1409                         break;
1410                 }
1411                 break;
1412
1413         case ICMP_RTRADVERT:
1414                 num_addrs = tvb_get_guint8(tvb, 4);
1415                 proto_tree_add_text(icmp_tree, tvb, 4, 1,
1416                                     "Number of addresses: %u", num_addrs);
1417                 addr_entry_size = tvb_get_guint8(tvb, 5);
1418                 proto_tree_add_text(icmp_tree, tvb, 5, 1,
1419                                     "Address entry size: %u",
1420                                     addr_entry_size);
1421                 proto_tree_add_text(icmp_tree, tvb, 6, 2, "Lifetime: %s",
1422                                     time_secs_to_str(wmem_packet_scope(), tvb_get_ntohs
1423                                                      (tvb, 6)));
1424                 break;
1425
1426         case ICMP_PARAMPROB:
1427                 proto_tree_add_text(icmp_tree, tvb, 4, 1, "Pointer: %u",
1428                                     tvb_get_guint8(tvb, 4));
1429                 if (icmp_original_dgram_length > 0) {
1430                         ti = proto_tree_add_item(icmp_tree, hf_icmp_length,
1431                                                  tvb, 5, 1,
1432                                                  ENC_BIG_ENDIAN);
1433                         proto_item_append_text(ti,
1434                                                " Length of original datagram: %u",
1435                                                icmp_original_dgram_length *
1436                                                4);
1437                 }
1438                 break;
1439
1440         case ICMP_REDIRECT:
1441                 proto_tree_add_item(icmp_tree, hf_icmp_redir_gw, tvb, 4, 4,
1442                                     ENC_BIG_ENDIAN);
1443                 break;
1444
1445         case ICMP_TIMXCEED:
1446                 if (icmp_original_dgram_length > 0) {
1447                         ti = proto_tree_add_item(icmp_tree, hf_icmp_length,
1448                                                  tvb, 5, 1,
1449                                                  ENC_BIG_ENDIAN);
1450                         proto_item_append_text(ti,
1451                                                " Length of original datagram: %u",
1452                                                icmp_original_dgram_length *
1453                                                4);
1454                 }
1455         }
1456
1457         /* Decode the additional information in the packet.  */
1458         switch (icmp_type) {
1459         case ICMP_UNREACH:
1460         case ICMP_TIMXCEED:
1461         case ICMP_PARAMPROB:
1462         case ICMP_SOURCEQUENCH:
1463         case ICMP_REDIRECT:
1464                 /* Save the current value of the "we're inside an error packet"
1465                    flag, and set that flag; subdissectors may treat packets
1466                    that are the payload of error packets differently from
1467                    "real" packets. */
1468                 save_in_error_pkt = pinfo->flags.in_error_pkt;
1469                 pinfo->flags.in_error_pkt = TRUE;
1470
1471                 /* Decode the IP header and first 64 bits of data from the
1472                    original datagram. */
1473                 next_tvb = tvb_new_subset_remaining(tvb, 8);
1474
1475                 /* If the packet is compliant with RFC 4884, then it has
1476                  * icmp_original_dgram_length*4 bytes of original IP packet that needs
1477                  * to be decoded, followed by extension objects.
1478                  */
1479                 if (icmp_original_dgram_length
1480                     && (tvb_reported_length(tvb) >
1481                         (guint) (8 + icmp_original_dgram_length * 4))
1482                     && (tvb_get_ntohs(tvb, 8 + 2) >
1483                         (guint) icmp_original_dgram_length * 4)) {
1484                         set_actual_length(next_tvb,
1485                                           icmp_original_dgram_length * 4);
1486                 } else {
1487                         /* There is a collision between RFC 1812 and draft-ietf-mpls-icmp-02.
1488                            We don't know how to decode the 128th and following bytes of the ICMP payload.
1489                            According to draft-ietf-mpls-icmp-02, these bytes should be decoded as MPLS extensios
1490                            whereas RFC 1812 tells us to decode them as a portion of the original packet.
1491                            Let the user decide.
1492
1493                            Here the user decided to favor MPLS extensions.
1494                            Force the IP dissector to decode only the first 128 bytes. */
1495                         if ((tvb_reported_length(tvb) > 8 + 128) &&
1496                             favor_icmp_mpls_ext
1497                             && (tvb_get_ntohs(tvb, 8 + 2) > 128)) {
1498                                 set_actual_length(next_tvb, 128);
1499                         }
1500                 }
1501
1502                 call_dissector(ip_handle, next_tvb, pinfo, icmp_tree);
1503
1504                 /* Restore the "we're inside an error packet" flag. */
1505                 pinfo->flags.in_error_pkt = save_in_error_pkt;
1506
1507                 /* Decode MPLS extensions if the payload has at least 128 bytes, and
1508                    - the original packet in the ICMP payload has less than 128 bytes, or
1509                    - the user favors the MPLS extensions analysis */
1510                 if ((tvb_reported_length(tvb) > 8 + 128)
1511                     && (tvb_get_ntohs(tvb, 8 + 2) <= 128
1512                         || favor_icmp_mpls_ext)) {
1513                         dissect_extensions(tvb, 8 + 128, icmp_tree);
1514                 }
1515                 break;
1516         case ICMP_ECHOREPLY:
1517         case ICMP_ECHO:
1518                 if (icmp_type == ICMP_ECHOREPLY) {
1519                         if (!pinfo->flags.in_error_pkt) {
1520                                 conv_key[0] =
1521                                     (guint32) tvb_get_ntohs(tvb, 2);
1522                                 if (pinfo->flags.in_gre_pkt)
1523                                         conv_key[0] |= 0x00010000;      /* set a bit for "in GRE" */
1524                                 conv_key[1] =
1525                                     (guint32) ((tvb_get_ntohs(tvb, 4) <<
1526                                                 16) | tvb_get_ntohs(tvb,
1527                                                                     6));
1528                                 trans =
1529                                     transaction_end(pinfo, icmp_tree,
1530                                                     conv_key);
1531                         }
1532                 } else {
1533                         if (!pinfo->flags.in_error_pkt) {
1534                                 guint16 tmp[2];
1535
1536                                 tmp[0] = ~tvb_get_ntohs(tvb, 2);
1537                                 tmp[1] = ~0x0800;       /* The difference between echo request & reply */
1538                                 conv_key[0] =
1539                                     ip_checksum((guint8 *) & tmp,
1540                                                 sizeof(tmp));
1541                                 if (conv_key[0] == 0) {
1542                                         conv_key[0] = 0xffff;
1543                                 }
1544                                 if (pinfo->flags.in_gre_pkt) {
1545                                         conv_key[0] |= 0x00010000;      /* set a bit for "in GRE" */
1546                                 }
1547                                 conv_key[1] =
1548                                     (guint32) ((tvb_get_ntohs(tvb, 4) <<
1549                                                 16) | tvb_get_ntohs(tvb,
1550                                                                     6));
1551                                 trans =
1552                                     transaction_start(pinfo, icmp_tree,
1553                                                       conv_key);
1554                         }
1555                 }
1556
1557                 /* Make sure we have enough bytes in the payload before trying to
1558                  * see if the data looks like a timestamp; otherwise we'll get
1559                  * malformed packets as we try to access data that isn't there. */
1560                 if (tvb_length_remaining(tvb, 8) < 8) {
1561                         if (tvb_length_remaining(tvb, 8) > 0) {
1562                                 call_dissector(data_handle,
1563                                                tvb_new_subset_remaining
1564                                                (tvb, 8), pinfo, icmp_tree);
1565                         }
1566                         break;
1567                 }
1568
1569                 /* Interpret the first 8 bytes of the icmp data as a timestamp
1570                  * But only if it does look like it's a timestamp.
1571                  *
1572                  * FIXME:
1573                  *    Timestamps could be in different formats depending on the OS
1574                  */
1575                 ts.secs = tvb_get_ntohl(tvb, 8);
1576                 ts.nsecs = tvb_get_ntohl(tvb, 8 + 4);   /* Leave at microsec resolution for now */
1577                 if ((guint32) (ts.secs - pinfo->fd->abs_ts.secs) >=
1578                     3600 * 24 || ts.nsecs >= 1000000) {
1579                         /* Timestamp does not look right in BE, try LE representation */
1580                         ts.secs = tvb_get_letohl(tvb, 8);
1581                         ts.nsecs = tvb_get_letohl(tvb, 8 + 4);  /* Leave at microsec resolution for now */
1582                 }
1583                 if ((guint32) (ts.secs - pinfo->fd->abs_ts.secs) <
1584                     3600 * 24 && ts.nsecs < 1000000) {
1585                         ts.nsecs *= 1000;       /* Convert to nanosec resolution */
1586                         proto_tree_add_time(icmp_tree, hf_icmp_data_time,
1587                                             tvb, 8, 8, &ts);
1588                         nstime_delta(&time_relative, &pinfo->fd->abs_ts,
1589                                      &ts);
1590                         ti = proto_tree_add_time(icmp_tree,
1591                                                  hf_icmp_data_time_relative,
1592                                                  tvb, 8, 8,
1593                                                  &time_relative);
1594                         PROTO_ITEM_SET_GENERATED(ti);
1595                         call_dissector(data_handle,
1596                                        tvb_new_subset_remaining(tvb,
1597                                                                 8 + 8),
1598                                        pinfo, icmp_tree);
1599                 } else {
1600                         call_dissector(data_handle,
1601                                        tvb_new_subset_remaining(tvb, 8),
1602                                        pinfo, icmp_tree);
1603                 }
1604                 break;
1605
1606         case ICMP_RTRADVERT:
1607                 if (addr_entry_size == 2) {
1608                         for (i = 0; i < num_addrs; i++) {
1609                                 proto_tree_add_text(icmp_tree, tvb,
1610                                                     8 + (i * 8), 4,
1611                                                     "Router address: %s",
1612                                                     tvb_ip_to_str(tvb,
1613                                                                   8 +
1614                                                                   (i *
1615                                                                    8)));
1616                                 proto_tree_add_text(icmp_tree, tvb,
1617                                                     12 + (i * 8), 4,
1618                                                     "Preference level: %d",
1619                                                     tvb_get_ntohl(tvb,
1620                                                                   12 +
1621                                                                   (i *
1622                                                                    8)));
1623                         }
1624                         if ((icmp_code == 0) || (icmp_code == 16)) {
1625                                 /* Mobile-Ip */
1626                                 dissect_mip_extensions(tvb, 8 + i * 8,
1627                                                        icmp_tree);
1628                         }
1629                 } else {
1630                         call_dissector(data_handle,
1631                                        tvb_new_subset_remaining(tvb, 8),
1632                                        pinfo, icmp_tree);
1633                 }
1634                 break;
1635
1636         case ICMP_TSTAMP:
1637         case ICMP_TSTAMPREPLY:
1638                 {
1639                         guint32 frame_ts, orig_ts;
1640
1641                         frame_ts = (guint32)(((pinfo->fd->abs_ts.secs * 1000) +
1642                                     (pinfo->fd->abs_ts.nsecs / 1000000)) %
1643                             86400000);
1644
1645                         orig_ts =
1646                             get_best_guess_mstimeofday(tvb, 8, frame_ts);
1647                         proto_tree_add_text(icmp_tree, tvb, 8, 4,
1648                                             "Originate timestamp: %s after midnight UTC",
1649                                             time_msecs_to_str(wmem_packet_scope(), orig_ts));
1650
1651                         proto_tree_add_text(icmp_tree, tvb, 12, 4,
1652                                             "Receive timestamp: %s after midnight UTC",
1653                                             time_msecs_to_str
1654                                             (wmem_packet_scope(), get_best_guess_mstimeofday
1655                                              (tvb, 12, orig_ts)));
1656                         proto_tree_add_text(icmp_tree, tvb, 16, 4,
1657                                             "Transmit timestamp: %s after midnight UTC",
1658                                             time_msecs_to_str
1659                                             (wmem_packet_scope(), get_best_guess_mstimeofday
1660                                              (tvb, 16, orig_ts)));
1661                 }
1662                 break;
1663
1664         case ICMP_MASKREQ:
1665         case ICMP_MASKREPLY:
1666                 proto_tree_add_text(icmp_tree, tvb, 8, 4,
1667                                     "Address mask: %s (0x%08x)",
1668                                     tvb_ip_to_str(tvb, 8),
1669                                     tvb_get_ntohl(tvb, 8));
1670                 break;
1671         }
1672
1673         if (trans) {
1674                 tap_queue_packet(icmp_tap, pinfo, trans);
1675         }
1676
1677         return tvb_length(tvb);
1678 }
1679
1680 void proto_register_icmp(void)
1681 {
1682         static hf_register_info hf[] = {
1683                 {&hf_icmp_type,
1684                  {"Type", "icmp.type", FT_UINT8, BASE_DEC, NULL, 0x0,
1685                   NULL, HFILL}},
1686
1687                 {&hf_icmp_code,
1688                  {"Code", "icmp.code", FT_UINT8, BASE_DEC, NULL, 0x0,
1689                   NULL, HFILL}},
1690
1691                 {&hf_icmp_checksum,
1692                  {"Checksum", "icmp.checksum", FT_UINT16, BASE_HEX, NULL,
1693                   0x0,
1694                   NULL, HFILL}},
1695
1696                 {&hf_icmp_checksum_bad,
1697                  {"Bad Checksum", "icmp.checksum_bad", FT_BOOLEAN,
1698                   BASE_NONE, NULL, 0x0,
1699                   NULL, HFILL}},
1700
1701                 {&hf_icmp_ident,
1702                  {"Identifier (BE)", "icmp.ident", FT_UINT16, BASE_DEC_HEX,
1703                   NULL, 0x0,
1704                   "Identifier (big endian representation)", HFILL}},
1705
1706                 {&hf_icmp_ident_le,
1707                  {"Identifier (LE)", "icmp.ident", FT_UINT16, BASE_DEC_HEX,
1708                   NULL, 0x0,
1709                   "Identifier (little endian representation)", HFILL}},
1710
1711                 {&hf_icmp_seq_num,
1712                  {"Sequence number (BE)", "icmp.seq", FT_UINT16,
1713                   BASE_DEC_HEX, NULL, 0x0,
1714                   "Sequence number (big endian representation)", HFILL}},
1715
1716                 {&hf_icmp_seq_num_le,
1717                  {"Sequence number (LE)", "icmp.seq_le", FT_UINT16,
1718                   BASE_DEC_HEX, NULL,
1719                   0x0, "Sequence number (little endian representation)",
1720                   HFILL}},
1721
1722                 {&hf_icmp_mtu,
1723                  {"MTU of next hop", "icmp.mtu", FT_UINT16, BASE_DEC, NULL,
1724                   0x0,
1725                   NULL, HFILL}},
1726
1727                 {&hf_icmp_redir_gw,
1728                  {"Gateway address", "icmp.redir_gw", FT_IPv4, BASE_NONE,
1729                   NULL, 0x0,
1730                   NULL, HFILL}},
1731
1732                 {&hf_icmp_mip_type,
1733                  {"Extension Type", "icmp.mip.type", FT_UINT8, BASE_DEC,
1734                   VALS(mip_extensions), 0x0, NULL, HFILL}},
1735
1736                 {&hf_icmp_mip_length,
1737                  {"Length", "icmp.mip.length", FT_UINT8, BASE_DEC, NULL,
1738                   0x0,
1739                   NULL, HFILL}},
1740
1741                 {&hf_icmp_mip_prefix_length,
1742                  {"Prefix Length", "icmp.mip.prefixlength", FT_UINT8,
1743                   BASE_DEC, NULL, 0x0,
1744                   NULL, HFILL}},
1745
1746                 {&hf_icmp_mip_seq,
1747                  {"Sequence Number", "icmp.mip.seq", FT_UINT16, BASE_DEC,
1748                   NULL, 0x0,
1749                   NULL, HFILL}},
1750
1751                 {&hf_icmp_mip_life,
1752                  {"Registration Lifetime", "icmp.mip.life", FT_UINT16,
1753                   BASE_DEC, NULL,
1754                   0x0,
1755                   NULL, HFILL}},
1756
1757                 {&hf_icmp_mip_flags,
1758                  {"Flags", "icmp.mip.flags", FT_UINT16, BASE_HEX, NULL,
1759                   0x0,
1760                   NULL, HFILL}},
1761
1762                 {&hf_icmp_mip_r,
1763                  {"Registration Required", "icmp.mip.r", FT_BOOLEAN, 16,
1764                   NULL, 0x8000,
1765                   "Registration with this FA is required", HFILL}},
1766
1767                 {&hf_icmp_mip_b,
1768                  {"Busy", "icmp.mip.b", FT_BOOLEAN, 16, NULL, 0x4000,
1769                   "This FA will not accept requests at this time", HFILL}},
1770
1771                 {&hf_icmp_mip_h,
1772                  {"Home Agent", "icmp.mip.h", FT_BOOLEAN, 16, NULL, 0x2000,
1773                   "Home Agent Services Offered", HFILL}},
1774
1775                 {&hf_icmp_mip_f,
1776                  {"Foreign Agent", "icmp.mip.f", FT_BOOLEAN, 16, NULL,
1777                   0x1000,
1778                   "Foreign Agent Services Offered", HFILL}},
1779
1780                 {&hf_icmp_mip_m,
1781                  {"Minimal Encapsulation", "icmp.mip.m", FT_BOOLEAN, 16,
1782                   NULL, 0x0800,
1783                   "Minimal encapsulation tunneled datagram support",
1784                   HFILL}},
1785
1786                 {&hf_icmp_mip_g,
1787                  {"GRE", "icmp.mip.g", FT_BOOLEAN, 16, NULL, 0x0400,
1788                   "GRE encapsulated tunneled datagram support", HFILL}},
1789
1790                 {&hf_icmp_mip_v,
1791                  {"VJ Comp", "icmp.mip.v", FT_BOOLEAN, 16, NULL, 0x0200,
1792                   "Van Jacobson Header Compression Support", HFILL}},
1793
1794                 {&hf_icmp_mip_rt,
1795                  {"Reverse tunneling", "icmp.mip.rt", FT_BOOLEAN, 16, NULL,
1796                   0x0100,
1797                   "Reverse tunneling support", HFILL}},
1798
1799                 {&hf_icmp_mip_u,
1800                  {"UDP tunneling", "icmp.mip.u", FT_BOOLEAN, 16, NULL,
1801                   0x0080,
1802                   "UDP tunneling support", HFILL}},
1803
1804                 {&hf_icmp_mip_x,
1805                  {"Revocation support", "icmp.mip.x", FT_BOOLEAN, 16, NULL,
1806                   0x0040,
1807                   "Registration revocation support", HFILL}},
1808
1809                 {&hf_icmp_mip_reserved,
1810                  {"Reserved", "icmp.mip.reserved", FT_UINT16, BASE_HEX,
1811                   NULL, 0x003f,
1812                   NULL, HFILL}},
1813
1814                 {&hf_icmp_mip_coa,
1815                  {"Care-Of-Address", "icmp.mip.coa", FT_IPv4, BASE_NONE,
1816                   NULL, 0x0,
1817                   NULL, HFILL}},
1818
1819                 {&hf_icmp_mip_challenge,
1820                  {"Challenge", "icmp.mip.challenge", FT_BYTES, BASE_NONE,
1821                   NULL, 0x0,
1822                   NULL, HFILL}},
1823
1824                 {&hf_icmp_ext,
1825                  {"ICMP Extensions", "icmp.ext", FT_NONE, BASE_NONE, NULL,
1826                   0x0,
1827                   NULL, HFILL}},
1828
1829                 {&hf_icmp_ext_version,
1830                  {"Version", "icmp.ext.version", FT_UINT8, BASE_DEC, NULL,
1831                   0x0,
1832                   NULL, HFILL}},
1833
1834                 {&hf_icmp_ext_reserved,
1835                  {"Reserved", "icmp.ext.res", FT_UINT16, BASE_HEX, NULL,
1836                   0x0fff,
1837                   NULL, HFILL}},
1838
1839                 {&hf_icmp_ext_checksum,
1840                  {"Checksum", "icmp.ext.checksum", FT_UINT16, BASE_HEX,
1841                   NULL, 0x0,
1842                   NULL, HFILL}},
1843
1844                 {&hf_icmp_ext_checksum_bad,
1845                  {"Bad Checksum", "icmp.ext.checksum_bad", FT_BOOLEAN,
1846                   BASE_NONE, NULL,
1847                   0x0,
1848                   NULL, HFILL}},
1849
1850                 {&hf_icmp_ext_length,
1851                  {"Length", "icmp.ext.length", FT_UINT16, BASE_DEC, NULL,
1852                   0x0,
1853                   NULL, HFILL}},
1854
1855                 {&hf_icmp_ext_class,
1856                  {"Class", "icmp.ext.class", FT_UINT8, BASE_DEC, NULL, 0x0,
1857                   NULL, HFILL}},
1858
1859                 {&hf_icmp_ext_c_type,
1860                  {"C-Type", "icmp.ext.ctype", FT_UINT8, BASE_DEC, NULL,
1861                   0x0,
1862                   NULL, HFILL}},
1863
1864                 {&hf_icmp_mpls_label,
1865                  {"Label", "icmp.mpls.label", FT_UINT24, BASE_DEC, NULL,
1866                   0x00fffff0,
1867                   NULL, HFILL}},
1868
1869                 {&hf_icmp_mpls_exp,
1870                  {"Experimental", "icmp.mpls.exp", FT_UINT24, BASE_DEC,
1871                   NULL, 0x0e,
1872                   NULL, HFILL}},
1873
1874                 {&hf_icmp_mpls_s,
1875                  {"Stack bit", "icmp.mpls.s", FT_BOOLEAN, 24,
1876                   TFS(&tfs_set_notset), 0x01,
1877                   NULL, HFILL}},
1878
1879                 {&hf_icmp_mpls_ttl,
1880                  {"Time to live", "icmp.mpls.ttl", FT_UINT8, BASE_DEC,
1881                   NULL, 0x0,
1882                   NULL, HFILL}},
1883
1884                 {&hf_icmp_resp_in,
1885                  {"Response frame", "icmp.resp_in", FT_FRAMENUM, BASE_NONE,
1886                   NULL, 0x0,
1887                   "The frame number of the corresponding response",
1888                   HFILL}},
1889
1890                 {&hf_icmp_no_resp,
1891                  {"No response seen", "icmp.no_resp", FT_NONE, BASE_NONE,
1892                   NULL, 0x0,
1893                   "No corresponding response frame was seen",
1894                   HFILL}},
1895
1896                 {&hf_icmp_resp_to,
1897                  {"Request frame", "icmp.resp_to", FT_FRAMENUM, BASE_NONE,
1898                   NULL, 0x0,
1899                   "The frame number of the corresponding request", HFILL}},
1900
1901                 {&hf_icmp_resptime,
1902                  {"Response time", "icmp.resptime", FT_DOUBLE, BASE_NONE,
1903                   NULL, 0x0,
1904                   "The time between the request and the response, in ms.",
1905                   HFILL}},
1906
1907                 {&hf_icmp_data_time,
1908                  {"Timestamp from icmp data", "icmp.data_time",
1909                   FT_ABSOLUTE_TIME,
1910                   ABSOLUTE_TIME_LOCAL, NULL, 0x0,
1911                   "The timestamp in the first 8 bytes of the icmp data",
1912                   HFILL}},
1913
1914                 {&hf_icmp_data_time_relative,
1915                  {"Timestamp from icmp data (relative)",
1916                   "icmp.data_time_relative",
1917                   FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
1918                   "The timestamp of the packet, relative to the timestamp in the first 8 bytes of the icmp data",
1919                   HFILL}},
1920
1921                 {&hf_icmp_length,
1922                  {"Length of original datagram", "icmp.length", FT_UINT8,
1923                   BASE_DEC, NULL,
1924                   0x0,
1925                   "The length of the original datagram", HFILL}},
1926                 {&hf_icmp_int_info_role,
1927                  {"Interface Role", "icmp.int_info.role",
1928                   FT_UINT8, BASE_DEC, VALS(interface_role_str),
1929                   INT_INFO_INTERFACE_ROLE,
1930                   NULL, HFILL}},
1931                 {&hf_icmp_int_info_reserved,
1932                  {"Reserved", "icmp.int_info.reserved",
1933                   FT_UINT8, BASE_DEC, NULL, INT_INFO_RESERVED,
1934                   NULL, HFILL}},
1935                 {&hf_icmp_int_info_ifindex,
1936                  {"ifIndex", "icmp.int_info.ifindex", FT_BOOLEAN, 8, NULL,
1937                   INT_INFO_IFINDEX,
1938                   "True: ifIndex of the interface included; False: ifIndex of the interface not included ",
1939                   HFILL}},
1940                 {&hf_icmp_int_info_ipaddr,
1941                  {"IP Address", "icmp.int_info.ipaddr", FT_BOOLEAN, 8,
1942                   NULL,
1943                   INT_INFO_IPADDR,
1944                   "True: IP Address Sub-Object present; False: IP Address Sub-Object not present",
1945                   HFILL}},
1946                 {&hf_icmp_int_info_name,
1947                  {"Interface Name", "icmp.int_info.name", FT_BOOLEAN, 8,
1948                   NULL,
1949                   INT_INFO_NAME,
1950                   "True: Interface Name Sub-Object present; False: Interface Name Sub-Object not present",
1951                   HFILL}},
1952                 {&hf_icmp_int_info_mtu,
1953                  {"MTU", "icmp.int_info.mtu", FT_BOOLEAN, 8, NULL,
1954                   INT_INFO_MTU,
1955                   "True: MTU present; False: MTU not present", HFILL}},
1956                 {&hf_icmp_int_info_afi,
1957                  {"Address Family Identifier", "icmp.int_info.afi",
1958                   FT_UINT16, BASE_DEC,
1959                   NULL, 0x0,
1960                   "Address Family of the interface address", HFILL}},
1961                 {&hf_icmp_int_info_ipv4,
1962                  {"Source", "icmp.int_info.ipv4", FT_IPv4, BASE_NONE, NULL,
1963                   0x0,
1964                   NULL, HFILL}},
1965                 {&hf_icmp_int_info_ipv6,
1966                  {"Source", "icmp.int_info.ipv6", FT_IPv6, BASE_NONE, NULL,
1967                   0x0,
1968                   NULL, HFILL}}
1969         };
1970
1971         static gint *ett[] = {
1972                 &ett_icmp,
1973                 &ett_icmp_mip,
1974                 &ett_icmp_mip_flags,
1975                 /* MPLS extensions */
1976                 &ett_icmp_ext,
1977                 &ett_icmp_ext_object,
1978                 &ett_icmp_mpls_stack_object,
1979                 /* Interface Information Object RFC 5837 */
1980                 &ett_icmp_interface_info_object,
1981                 &ett_icmp_interface_ipaddr,
1982                 &ett_icmp_interface_name
1983         };
1984
1985         static ei_register_info ei[] = {
1986                 { &ei_icmp_resp_not_found, { "icmp.resp_not_found", PI_SEQUENCE, PI_WARN, "Response not found", EXPFILL }},
1987         };
1988
1989         module_t *icmp_module;
1990         expert_module_t* expert_icmp;
1991
1992         proto_icmp =
1993             proto_register_protocol("Internet Control Message Protocol",
1994                                     "ICMP", "icmp");
1995         proto_register_field_array(proto_icmp, hf, array_length(hf));
1996         expert_icmp = expert_register_protocol(proto_icmp);
1997         expert_register_field_array(expert_icmp, ei, array_length(ei));
1998         proto_register_subtree_array(ett, array_length(ett));
1999
2000         icmp_module = prefs_register_protocol(proto_icmp, NULL);
2001
2002         prefs_register_bool_preference(icmp_module, "favor_icmp_mpls",
2003                                        "Favor ICMP extensions for MPLS",
2004                                        "Whether the 128th and following bytes of the ICMP payload should be decoded as MPLS extensions or as a portion of the original packet",
2005                                        &favor_icmp_mpls_ext);
2006
2007         new_register_dissector("icmp", dissect_icmp, proto_icmp);
2008         icmp_tap = register_tap("icmp");
2009 }
2010
2011 void proto_reg_handoff_icmp(void)
2012 {
2013         dissector_handle_t icmp_handle;
2014
2015         /*
2016          * Get handle for the IP dissector.
2017          */
2018         ip_handle = find_dissector("ip");
2019         icmp_handle = find_dissector("icmp");
2020         data_handle = find_dissector("data");
2021
2022         dissector_add_uint("ip.proto", IP_PROTO_ICMP, icmp_handle);
2023 }