From Didier Gautheron:
[obnox/wireshark/wip.git] / epan / dissectors / packet-icmp.c
1 /* packet-icmp.c
2  * Routines for ICMP - Internet Control Message Protocol
3  *
4  * $Id$
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * Monday, June 27, 2005
11  * Support for the ICMP extensions for MPLS
12  * (http://www.ietf.org/proceedings/01aug/I-D/draft-ietf-mpls-icmp-02.txt)
13  * by   Maria-Luiza Crivat <luizacri@gmail.com>
14  * &    Brice Augustin <bricecotte@gmail.com>
15  *
16  * This program is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU General Public License
18  * as published by the Free Software Foundation; either version 2
19  * of the License, or (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, write to the Free Software
28  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
29  */
30
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34
35 #include <stdio.h>
36 #include <string.h>
37 #include <glib.h>
38
39 #include <epan/packet.h>
40 #include <epan/ipproto.h>
41 #include <epan/prefs.h>
42 #include <epan/in_cksum.h>
43
44 #include "packet-ip.h"
45
46
47 /* Decode the end of the ICMP payload as ICMP MPLS extensions
48 if the packet in the payload has more than 128 bytes */
49 static gboolean favor_icmp_mpls_ext = FALSE;
50
51 static int proto_icmp = -1;
52 static int hf_icmp_type = -1;
53 static int hf_icmp_code = -1;
54 static int hf_icmp_checksum = -1;
55 static int hf_icmp_checksum_bad = -1;
56 static int hf_icmp_ident = -1;
57 static int hf_icmp_seq_num = -1;
58 static int hf_icmp_mtu = -1;
59 static int hf_icmp_redir_gw = -1;
60
61
62 /* Mobile ip */
63 static int hf_icmp_mip_type = -1;
64 static int hf_icmp_mip_length = -1;
65 static int hf_icmp_mip_prefix_length = -1;
66 static int hf_icmp_mip_seq = -1;
67 static int hf_icmp_mip_life = -1;
68 static int hf_icmp_mip_flags = -1;
69 static int hf_icmp_mip_r = -1;
70 static int hf_icmp_mip_b = -1;
71 static int hf_icmp_mip_h = -1;
72 static int hf_icmp_mip_f = -1;
73 static int hf_icmp_mip_m = -1;
74 static int hf_icmp_mip_g = -1;
75 static int hf_icmp_mip_v = -1;
76 static int hf_icmp_mip_rt = -1;
77 static int hf_icmp_mip_u = -1;
78 static int hf_icmp_mip_x = -1;
79 static int hf_icmp_mip_reserved = -1;
80 static int hf_icmp_mip_coa = -1;
81 static int hf_icmp_mip_challenge = -1;
82
83 /* MPLS extensions */
84 static int hf_icmp_mpls = -1;
85 static int hf_icmp_mpls_version = -1;
86 static int hf_icmp_mpls_reserved = -1;
87 static int hf_icmp_mpls_checksum = -1;
88 static int hf_icmp_mpls_checksum_bad = -1;
89 static int hf_icmp_mpls_length = -1;
90 static int hf_icmp_mpls_class = -1;
91 static int hf_icmp_mpls_c_type = -1;
92 static int hf_icmp_mpls_label = -1;
93 static int hf_icmp_mpls_exp = -1;
94 static int hf_icmp_mpls_s = -1;
95 static int hf_icmp_mpls_ttl = -1;
96
97 static gint ett_icmp = -1;
98 static gint ett_icmp_mip = -1;
99 static gint ett_icmp_mip_flags = -1;
100
101 /* MPLS extensions */
102 static gint ett_icmp_mpls = -1;
103 static gint ett_icmp_mpls_object = -1;
104 static gint ett_icmp_mpls_stack_object = -1;
105
106 /* ICMP definitions */
107
108 #define ICMP_ECHOREPLY     0
109 #define ICMP_UNREACH       3
110 #define ICMP_SOURCEQUENCH  4
111 #define ICMP_REDIRECT      5
112 #define ICMP_ALTHOST       6
113 #define ICMP_ECHO          8
114 #define ICMP_RTRADVERT     9
115 #define ICMP_RTRSOLICIT   10
116 #define ICMP_TIMXCEED     11
117 #define ICMP_PARAMPROB    12
118 #define ICMP_TSTAMP       13
119 #define ICMP_TSTAMPREPLY  14
120 #define ICMP_IREQ         15
121 #define ICMP_IREQREPLY    16
122 #define ICMP_MASKREQ      17
123 #define ICMP_MASKREPLY    18
124 #define ICMP_PHOTURIS     40
125
126 /* ICMP UNREACHABLE */
127
128 #define ICMP_NET_UNREACH        0       /* Network Unreachable */
129 #define ICMP_HOST_UNREACH       1       /* Host Unreachable */
130 #define ICMP_PROT_UNREACH       2       /* Protocol Unreachable */
131 #define ICMP_PORT_UNREACH       3       /* Port Unreachable */
132 #define ICMP_FRAG_NEEDED        4       /* Fragmentation Needed/DF set */
133 #define ICMP_SR_FAILED          5       /* Source Route failed */
134 #define ICMP_NET_UNKNOWN        6
135 #define ICMP_HOST_UNKNOWN       7
136 #define ICMP_HOST_ISOLATED      8
137 #define ICMP_NET_ANO            9
138 #define ICMP_HOST_ANO           10
139 #define ICMP_NET_UNR_TOS        11
140 #define ICMP_HOST_UNR_TOS       12
141 #define ICMP_PKT_FILTERED       13      /* Packet filtered */
142 #define ICMP_PREC_VIOLATION     14      /* Precedence violation */
143 #define ICMP_PREC_CUTOFF        15      /* Precedence cut off */
144
145 #define ICMP_MIP_EXTENSION_PAD  0
146 #define ICMP_MIP_MOB_AGENT_ADV  16
147 #define ICMP_MIP_PREFIX_LENGTHS 19
148 #define ICMP_MIP_CHALLENGE      24
149
150 static dissector_handle_t ip_handle;
151 static dissector_handle_t data_handle;
152
153 static const value_string icmp_type_str[] = {
154   { ICMP_ECHOREPLY,    "Echo (ping) reply" },
155   { 1,                 "Reserved" },
156   { 2,                 "Reserved" },
157   { ICMP_UNREACH,      "Destination unreachable" },
158   { ICMP_SOURCEQUENCH, "Source quench (flow control)" },
159   { ICMP_REDIRECT,     "Redirect" },
160   { ICMP_ALTHOST,      "Alternate host address" },
161   { ICMP_ECHO,         "Echo (ping) request" },
162   { ICMP_RTRADVERT,    "Router advertisement" },
163   { ICMP_RTRSOLICIT,   "Router solicitation" },
164   { ICMP_TIMXCEED,     "Time-to-live exceeded" },
165   { ICMP_PARAMPROB,    "Parameter problem" },
166   { ICMP_TSTAMP,       "Timestamp request" },
167   { ICMP_TSTAMPREPLY,  "Timestamp reply" },
168   { ICMP_IREQ,         "Information request" },
169   { ICMP_IREQREPLY,    "Information reply" },
170   { ICMP_MASKREQ,      "Address mask request" },
171   { ICMP_MASKREPLY,    "Address mask reply" },
172   { 19,                "Reserved (for security)" },
173   { 30,                "Traceroute" },
174   { 31,                "Datagram Conversion Error" },
175   { 32,                "Mobile Host Redirect" },
176   { 33,                "IPv6 Where-Are-You" },
177   { 34,                "IPv6 I-Am-Here" },
178   { 35,                "Mobile Registration Request" },
179   { 36,                "Mobile Registration Reply" },
180   { 37,                "Domain Name Request" },
181   { 38,                "Domain Name Reply" },
182   { 39,                "SKIP" },
183   { ICMP_PHOTURIS,     "Photuris" },
184   { 41,                "Experimental mobility protocols" },
185   { 0, NULL }
186 };
187
188 static const value_string unreach_code_str[] = {
189   { ICMP_NET_UNREACH,    "Network unreachable" },
190   { ICMP_HOST_UNREACH,   "Host unreachable" },
191   { ICMP_PROT_UNREACH,   "Protocol unreachable" },
192   { ICMP_PORT_UNREACH,   "Port unreachable" },
193   { ICMP_FRAG_NEEDED,    "Fragmentation needed" },
194   { ICMP_SR_FAILED,      "Source route failed" },
195   { ICMP_NET_UNKNOWN,    "Destination network unknown" },
196   { ICMP_HOST_UNKNOWN,   "Destination host unknown" },
197   { ICMP_HOST_ISOLATED,  "Source host isolated" },
198   { ICMP_NET_ANO,        "Network administratively prohibited" },
199   { ICMP_HOST_ANO,       "Host administratively prohibited" },
200   { ICMP_NET_UNR_TOS,    "Network unreachable for TOS" },
201   { ICMP_HOST_UNR_TOS,   "Host unreachable for TOS" },
202   { ICMP_PKT_FILTERED,   "Communication administratively filtered" },
203   { ICMP_PREC_VIOLATION, "Host precedence violation" },
204   { ICMP_PREC_CUTOFF,    "Precedence cutoff in effect" },
205   { 0, NULL }
206 };
207
208 static const value_string redir_code_str[] = {
209   { 0, "Redirect for network" },
210   { 1, "Redirect for host" },
211   { 2, "Redirect for TOS and network" },
212   { 3, "Redirect for TOS and host"},
213   { 0, NULL }
214 };
215
216 static const value_string alt_host_code_str[] = {
217   { 0, "Alternate address for host" },
218   { 0, NULL }
219 };
220
221 static const value_string rtradvert_code_str[] = {
222   { 0,  "Normal router advertisement" },
223   { 16, "Does not route common traffic" },
224   { 0, NULL }
225 };
226
227 static const value_string ttl_code_str[] = {
228   { 0, "Time to live exceeded in transit" },
229   { 1, "Fragment reassembly time exceeded" },
230   { 0, NULL }
231 };
232
233 static const value_string par_code_str[] = {
234   { 0, "Pointer indicates the error" },
235   { 1, "Required option missing" },
236   { 2, "Bad length" },
237   { 0, NULL }
238 };
239
240 static const value_string photuris_code_str[] = {
241   { 0, "Bad SPI" },
242   { 1, "Authentication Failed" },
243   { 2, "Decompression Failed" },
244   { 3, "Decryption Failed" },
245   { 4, "Need Authentication" },
246   { 5, "Need Authorization" },
247   { 0, NULL }
248 };
249
250 static const value_string mip_extensions[] = {
251   { ICMP_MIP_EXTENSION_PAD, "One byte padding extension"},  /* RFC 2002 */
252   { ICMP_MIP_MOB_AGENT_ADV, "Mobility Agent Advertisement Extension"},
253                                                             /* RFC 2002 */
254   { ICMP_MIP_PREFIX_LENGTHS, "Prefix Lengths Extension"},   /* RFC 2002 */
255   { ICMP_MIP_CHALLENGE, "Challenge Extension"},             /* RFC 3012 */
256   { 0, NULL}
257 };
258
259 #define MPLS_STACK_ENTRY_OBJECT_CLASS           1
260 #define MPLS_EXTENDED_PAYLOAD_OBJECT_CLASS      2
261
262 #define MPLS_STACK_ENTRY_C_TYPE                 1
263 #define MPLS_EXTENDED_PAYLOAD_C_TYPE            1
264
265 /* XXX no header defines these macros ??? */
266 #ifndef min
267 #define min(a,b) (((a)<(b))?(a):(b))
268 #endif
269
270 #ifndef max
271 #define max(a,b) (((a)>(b))?(a):(b))
272 #endif
273
274 /*
275  * Dissect the mobile ip advertisement extensions.
276  */
277 static void
278 dissect_mip_extensions(tvbuff_t *tvb, int offset, proto_tree *tree)
279 {
280   guint8       type;
281   guint8       length;
282   guint16      flags;
283   proto_item   *ti;
284   proto_tree   *mip_tree=NULL;
285   proto_tree   *flags_tree=NULL;
286   gint         numCOAs;
287   gint         i;
288
289   /* Not much to do if we're not parsing everything */
290   if (!tree) return;
291
292   while (tvb_reported_length_remaining(tvb, offset) > 0) {
293
294         type = tvb_get_guint8(tvb, offset + 0);
295         if (type)
296           length = tvb_get_guint8(tvb, offset + 1);
297         else
298           length=0;
299
300         ti = proto_tree_add_text(tree, tvb, offset,
301                                                          type?(length + 2):1,
302                                                          "Ext: %s",
303                                                          val_to_str(type, mip_extensions,
304                                                                                 "Unknown ext %u"));
305         mip_tree = proto_item_add_subtree(ti, ett_icmp_mip);
306
307
308         switch (type) {
309         case ICMP_MIP_EXTENSION_PAD:
310           /* One byte padding extension */
311           /* Add our fields */
312           /* type */
313           proto_tree_add_item(mip_tree, hf_icmp_mip_type, tvb, offset,
314                                                   1, FALSE);
315           offset++;
316           break;
317         case ICMP_MIP_MOB_AGENT_ADV:
318           /* Mobility Agent Advertisement Extension (RFC 2002)*/
319           /* Add our fields */
320           /* type */
321           proto_tree_add_item(mip_tree, hf_icmp_mip_type, tvb, offset,
322                                                   1, FALSE);
323           offset++;
324           /* length */
325           proto_tree_add_item(mip_tree, hf_icmp_mip_length, tvb, offset,
326                                                   1, FALSE);
327           offset++;
328           /* sequence number */
329           proto_tree_add_item(mip_tree, hf_icmp_mip_seq, tvb, offset,
330                                                   2, FALSE);
331           offset+=2;
332           /* Registration Lifetime */
333           proto_tree_add_item(mip_tree, hf_icmp_mip_life, tvb, offset,
334                                                   2, FALSE);
335           offset+=2;
336           /* flags */
337           flags = tvb_get_ntohs(tvb, offset);
338           ti = proto_tree_add_uint(mip_tree, hf_icmp_mip_flags, tvb, offset, 2, flags);
339           flags_tree = proto_item_add_subtree(ti, ett_icmp_mip_flags);
340           proto_tree_add_boolean(flags_tree, hf_icmp_mip_r, tvb, offset, 2, flags);
341           proto_tree_add_boolean(flags_tree, hf_icmp_mip_b, tvb, offset, 2, flags);
342           proto_tree_add_boolean(flags_tree, hf_icmp_mip_h, tvb, offset, 2, flags);
343           proto_tree_add_boolean(flags_tree, hf_icmp_mip_f, tvb, offset, 2, flags);
344           proto_tree_add_boolean(flags_tree, hf_icmp_mip_m, tvb, offset, 2, flags);
345           proto_tree_add_boolean(flags_tree, hf_icmp_mip_g, tvb, offset, 2, flags);
346           proto_tree_add_boolean(flags_tree, hf_icmp_mip_v, tvb, offset, 2, flags);
347           proto_tree_add_boolean(flags_tree, hf_icmp_mip_rt, tvb, offset, 2, flags);
348           proto_tree_add_boolean(flags_tree, hf_icmp_mip_u, tvb, offset, 2, flags);
349           proto_tree_add_boolean(flags_tree, hf_icmp_mip_x, tvb, offset, 2, flags);
350
351           /* Reserved */
352           proto_tree_add_uint(flags_tree, hf_icmp_mip_reserved, tvb, offset, 2, flags);
353           offset+=2;
354
355           /* COAs */
356           numCOAs = (length - 6) / 4;
357           for (i=0; i<numCOAs; i++) {
358                 proto_tree_add_item(mip_tree, hf_icmp_mip_coa, tvb, offset,
359                                                         4, FALSE);
360                 offset+=4;
361           }
362           break;
363         case ICMP_MIP_PREFIX_LENGTHS:
364           /* Prefix-Lengths Extension  (RFC 2002)*/
365           /* Add our fields */
366           /* type */
367           proto_tree_add_item(mip_tree, hf_icmp_mip_type, tvb, offset,
368                                                   1, FALSE);
369           offset++;
370           /* length */
371           proto_tree_add_item(mip_tree, hf_icmp_mip_length, tvb, offset,
372                                                   1, FALSE);
373           offset++;
374
375           /* prefix lengths */
376           for(i=0; i<length; i++) {
377                 proto_tree_add_item(mip_tree, hf_icmp_mip_prefix_length, tvb, offset,
378                                                         1, FALSE);
379                 offset++;
380           }
381           break;
382         case ICMP_MIP_CHALLENGE:
383           /* Challenge Extension  (RFC 3012)*/
384           /* type */
385           proto_tree_add_item(mip_tree, hf_icmp_mip_type, tvb, offset,
386                                                   1, FALSE);
387           offset++;
388           /* length */
389           proto_tree_add_item(mip_tree, hf_icmp_mip_length, tvb, offset,
390                                                   1, FALSE);
391           offset++;
392           /* challenge */
393           proto_tree_add_item(mip_tree, hf_icmp_mip_challenge, tvb, offset,
394                                                   length, FALSE);
395           offset+=length;
396
397           break;
398         default:
399           g_warning("Unknown type(%u)!  I hope the length is right (%u)",
400                                 type, length);
401           offset += length + 2;
402           break;
403         } /* switch type */
404   } /* end while */
405
406 } /* dissect_mip_extensions */
407
408 /*
409  * Dissect the MPLS extensions
410  */
411 static void
412 dissect_mpls_extensions(tvbuff_t *tvb, gint offset, proto_tree *tree)
413 {
414     guint8          version;
415     guint8          class_num;
416     guint8          c_type;
417     guint8          ttl;
418     guint8          tmp;
419     guint16         reserved;
420     guint16         cksum, computed_cksum;
421     guint16         obj_length, obj_trunc_length;
422     proto_item      *ti, *tf_object, *tf_entry, *hidden_item;
423     proto_tree      *mpls_tree=NULL, *mpls_object_tree, *mpls_stack_object_tree;
424     gint            obj_end_offset;
425     guint           reported_length;
426     guint           label;
427     gboolean        unknown_object;
428
429     if (!tree)
430         return;
431
432     reported_length = tvb_reported_length_remaining(tvb, offset);
433
434     if (reported_length < 4 /* Common header */)
435     {
436         proto_tree_add_text(tree, tvb, offset,
437                             reported_length,
438                             "MPLS Extensions (truncated)");
439         return;
440     }
441
442     /* Add a tree for the MPLS extensions */
443     ti = proto_tree_add_none_format(tree, hf_icmp_mpls, tvb,
444                                             offset, reported_length, "MPLS Extensions");
445
446     mpls_tree = proto_item_add_subtree(ti, ett_icmp_mpls);
447
448     /* Version */
449     version = hi_nibble(tvb_get_guint8(tvb, offset));
450     proto_tree_add_uint(mpls_tree, hf_icmp_mpls_version, tvb, offset, 1, version);
451
452     /* Reserved */
453     reserved = tvb_get_ntohs(tvb, offset) & 0x0fff;
454     proto_tree_add_uint_format(mpls_tree, hf_icmp_mpls_reserved,
455                                 tvb, offset, 2, reserved,
456                                 "Reserved: 0x%03x", reserved);
457
458     /* Checksum */
459     cksum = tvb_get_ntohs(tvb, offset + 2);
460
461     computed_cksum = ip_checksum(tvb_get_ptr(tvb, offset, reported_length),
462                                     reported_length);
463
464     if (computed_cksum == 0)
465     {
466         proto_tree_add_uint_format(mpls_tree, hf_icmp_mpls_checksum, tvb, offset + 2, 2,
467                                     cksum, "Checksum: 0x%04x [correct]", cksum);
468     }
469     else
470     {
471         hidden_item = proto_tree_add_boolean(mpls_tree, hf_icmp_mpls_checksum_bad, tvb,
472                                             offset + 2, 2, TRUE);
473         PROTO_ITEM_SET_HIDDEN(hidden_item);
474
475         proto_tree_add_uint_format(mpls_tree, hf_icmp_mpls_checksum, tvb, offset + 2, 2,
476                                     cksum,
477                                     "Checksum: 0x%04x [incorrect, should be 0x%04x]",
478                                     cksum, in_cksum_shouldbe(cksum, computed_cksum));
479     }
480
481     if (version != 1 && version != 2)
482     {
483         /* Unsupported version */
484         proto_item_append_text(ti, " (unsupported version)");
485         return;
486     }
487
488     /* Skip the common header */
489     offset += 4;
490
491     /* While there is enough room to read an object */
492     while (tvb_reported_length_remaining(tvb, offset) >= 4 /* Object header */)
493     {
494         /* Object length */
495         obj_length = tvb_get_ntohs(tvb, offset);
496
497         obj_trunc_length =  min(obj_length, tvb_reported_length_remaining(tvb, offset));
498
499         obj_end_offset = offset + obj_trunc_length;
500
501         /* Add a subtree for this object (the text will be reset later) */
502         tf_object = proto_tree_add_text(mpls_tree, tvb, offset,
503                                         max(obj_trunc_length, 4),
504                                         "Unknown object");
505
506         mpls_object_tree = proto_item_add_subtree(tf_object, ett_icmp_mpls_object);
507
508         proto_tree_add_uint(mpls_object_tree, hf_icmp_mpls_length, tvb, offset, 2, obj_length);
509
510         /* Class */
511         class_num = tvb_get_guint8(tvb, offset + 2);
512         proto_tree_add_uint(mpls_object_tree, hf_icmp_mpls_class, tvb, offset + 2, 1, class_num);
513
514         /* C-Type */
515         c_type = tvb_get_guint8(tvb, offset + 3);
516         proto_tree_add_uint(mpls_object_tree, hf_icmp_mpls_c_type, tvb, offset + 3, 1, c_type);
517
518         if (obj_length < 4 /* Object header */)
519         {
520             /* Thanks doc/README.developer :)) */
521             proto_item_set_text(tf_object, "Object with bad length");
522             break;
523         }
524
525         /* Skip the object header */
526         offset += 4;
527
528         /* Default cases will set this flag to TRUE */
529         unknown_object = FALSE;
530
531         switch (class_num)
532         {
533             case MPLS_STACK_ENTRY_OBJECT_CLASS:
534                 switch (c_type)
535                 {
536                     case MPLS_STACK_ENTRY_C_TYPE:
537
538                         proto_item_set_text(tf_object, "MPLS Stack Entry");
539
540                         /* For each entry */
541                         while (offset + 4 <= obj_end_offset)
542                         {
543                             if (tvb_reported_length_remaining(tvb, offset) < 4)
544                             {
545                                 /* Not enough room in the packet ! */
546                                 break;
547                             }
548
549                             /* Create a subtree for each entry (the text will be set later) */
550                             tf_entry = proto_tree_add_text(mpls_object_tree,
551                                                             tvb, offset, 4, " ");
552                             mpls_stack_object_tree = proto_item_add_subtree(tf_entry,
553                                                                             ett_icmp_mpls_stack_object);
554
555                             /* Label */
556                             label =  (guint)tvb_get_ntohs(tvb, offset);
557                             tmp = tvb_get_guint8(tvb, offset + 2);
558                             label = (label << 4) + (tmp >> 4);
559
560                             proto_tree_add_uint(mpls_stack_object_tree,
561                                                     hf_icmp_mpls_label,
562                                                     tvb,
563                                                     offset,
564                                                     3,
565                                                     label << 4);
566
567                             proto_item_set_text(tf_entry, "Label: %u", label);
568
569                             /* Experimental field (also called "CoS") */
570                             proto_tree_add_uint(mpls_stack_object_tree,
571                                                     hf_icmp_mpls_exp,
572                                                     tvb,
573                                                     offset + 2,
574                                                     1,
575                                                     tmp);
576
577                             proto_item_append_text(tf_entry, ", Exp: %u", (tmp >> 1) & 0x07);
578
579                             /* Stack bit */
580                             proto_tree_add_boolean(mpls_stack_object_tree,
581                                                     hf_icmp_mpls_s,
582                                                     tvb,
583                                                     offset + 2,
584                                                     1,
585                                                     tmp);
586
587                             proto_item_append_text(tf_entry, ", S: %u", tmp  & 0x01);
588
589                             /* TTL */
590                             ttl = tvb_get_guint8(tvb, offset + 3);
591
592                             proto_tree_add_item(mpls_stack_object_tree,
593                                                 hf_icmp_mpls_ttl,
594                                                 tvb,
595                                                 offset + 3,
596                                                 1,
597                                                 FALSE);
598
599                             proto_item_append_text(tf_entry, ", TTL: %u", ttl);
600
601                             /* Skip the entry */
602                             offset += 4;
603
604                         } /* end while */
605
606                         if (offset < obj_end_offset)
607                             proto_tree_add_text(mpls_object_tree, tvb,
608                                                 offset,
609                                                 obj_end_offset - offset,
610                                                 "%d junk bytes",
611                                                 obj_end_offset - offset);
612
613                         break;
614                     default:
615
616                         unknown_object = TRUE;
617
618                         break;
619                 } /* end switch c_type */
620                 break;
621             case MPLS_EXTENDED_PAYLOAD_OBJECT_CLASS:
622                 switch (c_type)
623                 {
624                     case MPLS_EXTENDED_PAYLOAD_C_TYPE:
625                         proto_item_set_text(tf_object, "Extended Payload");
626
627                         /* This object contains some portion of the original packet
628                         that could not fit in the 128 bytes of the ICMP payload */
629                         if (obj_trunc_length > 4)
630                             proto_tree_add_text(mpls_object_tree, tvb,
631                                                 offset, obj_trunc_length - 4,
632                                                 "Data (%d bytes)", obj_trunc_length - 4);
633
634                         break;
635                     default:
636
637                         unknown_object = TRUE;
638
639                         break;
640                 } /* end switch c_type */
641                 break;
642             default:
643
644                 unknown_object = TRUE;
645
646                 break;
647         } /* end switch class_num */
648
649         /* The switches couldn't decode the object */
650         if (unknown_object == TRUE)
651         {
652             proto_item_set_text(tf_object, "Unknown object (%d/%d)", class_num, c_type);
653
654             if (obj_trunc_length > 4)
655                 proto_tree_add_text(mpls_object_tree, tvb,
656                                     offset, obj_trunc_length - 4,
657                                     "Data (%d bytes)", obj_trunc_length - 4);
658         }
659
660         /* */
661         if (obj_trunc_length < obj_length)
662             proto_item_append_text(tf_object, " (truncated)");
663
664         /* Go to the end of the object */
665         offset = obj_end_offset;
666
667     } /* end while */
668 } /* end dissect_mpls_extensions */
669
670 /*
671  * RFC 792 for basic ICMP.
672  * RFC 1191 for ICMP_FRAG_NEEDED (with MTU of next hop).
673  * RFC 1256 for router discovery messages.
674  * RFC 2002 and 3012 for Mobile IP stuff.
675  */
676 static void
677 dissect_icmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
678 {
679   proto_tree *icmp_tree = NULL;
680   proto_item *ti;
681   guint8     icmp_type;
682   guint8     icmp_code;
683   guint      length, reported_length;
684   guint16    cksum, computed_cksum;
685   const gchar *type_str, *code_str;
686   guint8     num_addrs = 0;
687   guint8     addr_entry_size = 0;
688   int        i;
689   gboolean   save_in_error_pkt;
690   tvbuff_t   *next_tvb;
691   proto_item *item;
692
693   col_set_str(pinfo->cinfo, COL_PROTOCOL, "ICMP");
694   col_clear(pinfo->cinfo, COL_INFO);
695
696   /* To do: check for runts, errs, etc. */
697   icmp_type = tvb_get_guint8(tvb, 0);
698   icmp_code = tvb_get_guint8(tvb, 1);
699   cksum = tvb_get_ntohs(tvb, 2);
700
701   type_str = val_to_str_const (icmp_type, icmp_type_str, "Unknown ICMP (obsolete or malformed?)");
702
703   switch (icmp_type) {
704     case ICMP_UNREACH:
705       code_str = val_to_str (icmp_code, unreach_code_str, "Unknown code: %u");
706       break;
707     case ICMP_REDIRECT:
708       code_str = val_to_str (icmp_code, redir_code_str, "Unknown code: %u");
709       break;
710     case ICMP_ALTHOST:
711       code_str = val_to_str (icmp_code, alt_host_code_str, "Unknown code: %u");
712       break;
713     case ICMP_RTRADVERT:
714       switch (icmp_code) {
715       case 0: /* Mobile-Ip */
716       case 16: /* Mobile-Ip */
717         type_str = "Mobile IP Advertisement";
718         break;
719       } /* switch icmp_code */
720       code_str = val_to_str (icmp_code, rtradvert_code_str, "Unknown code: %u");
721       break;
722     case ICMP_TIMXCEED:
723       code_str = val_to_str (icmp_code, ttl_code_str, "Unknown code: %u");
724       break;
725     case ICMP_PARAMPROB:
726       code_str = val_to_str (icmp_code, par_code_str, "Unknown code: %u");
727       break;
728     case ICMP_PHOTURIS:
729       code_str = val_to_str (icmp_code, photuris_code_str, "Unknown code: %u");
730       break;
731     default:
732       code_str = NULL;
733       break;
734   }
735
736   col_set_str(pinfo->cinfo, COL_INFO, type_str);
737   if (code_str)
738     col_append_fstr(pinfo->cinfo, COL_INFO, " (%s)", code_str);
739
740   length = tvb_length(tvb);
741   reported_length = tvb_reported_length(tvb);
742
743   ti = proto_tree_add_item(tree, proto_icmp, tvb, 0, length, FALSE);
744   icmp_tree = proto_item_add_subtree(ti, ett_icmp);
745
746   ti = proto_tree_add_item(icmp_tree, hf_icmp_type, tvb, 0, 1, FALSE);
747   proto_item_append_text (ti, " (%s)", type_str);
748
749   ti = proto_tree_add_item(icmp_tree, hf_icmp_code, tvb, 1, 1, FALSE);
750   if (code_str)
751     proto_item_append_text (ti, " (%s)", code_str);
752
753   if (!pinfo->fragmented && length >= reported_length) {
754     /* The packet isn't part of a fragmented datagram and isn't
755        truncated, so we can checksum it. */
756
757     computed_cksum = ip_checksum(tvb_get_ptr(tvb, 0, reported_length),
758                                  reported_length);
759     if (computed_cksum == 0) {
760       proto_tree_add_uint_format(icmp_tree, hf_icmp_checksum, tvb, 2, 2,
761                                  cksum,
762                                  "Checksum: 0x%04x [correct]", cksum);
763     } else {
764       item = proto_tree_add_boolean(icmp_tree, hf_icmp_checksum_bad,
765                                     tvb, 2, 2, TRUE);
766       PROTO_ITEM_SET_HIDDEN(item);
767       proto_tree_add_uint_format(icmp_tree, hf_icmp_checksum, tvb, 2, 2,
768                                  cksum,
769                                  "Checksum: 0x%04x [incorrect, should be 0x%04x]",
770                                  cksum, in_cksum_shouldbe(cksum, computed_cksum));
771     }
772   } else {
773     proto_tree_add_uint(icmp_tree, hf_icmp_checksum, tvb, 2, 2, cksum);
774   }
775
776   /* Decode the second 4 bytes of the packet. */
777   switch (icmp_type) {
778       case ICMP_ECHOREPLY:
779       case ICMP_ECHO:
780       case ICMP_TSTAMP:
781       case ICMP_TSTAMPREPLY:
782       case ICMP_IREQ:
783       case ICMP_IREQREPLY:
784       case ICMP_MASKREQ:
785       case ICMP_MASKREPLY:
786         proto_tree_add_item(icmp_tree, hf_icmp_ident, tvb, 4, 2, FALSE);
787         proto_tree_add_item(icmp_tree, hf_icmp_seq_num, tvb, 6, 2, FALSE);
788         break;
789
790       case ICMP_UNREACH:
791         switch (icmp_code) {
792           case ICMP_FRAG_NEEDED:
793             proto_tree_add_item(icmp_tree, hf_icmp_mtu, tvb, 6, 2, FALSE);
794             break;
795         }
796         break;
797
798       case ICMP_RTRADVERT:
799         num_addrs = tvb_get_guint8(tvb, 4);
800         proto_tree_add_text(icmp_tree, tvb, 4, 1, "Number of addresses: %u",
801           num_addrs);
802         addr_entry_size = tvb_get_guint8(tvb, 5);
803         proto_tree_add_text(icmp_tree, tvb, 5, 1, "Address entry size: %u",
804           addr_entry_size);
805         proto_tree_add_text(icmp_tree, tvb, 6, 2, "Lifetime: %s",
806           time_secs_to_str(tvb_get_ntohs(tvb, 6)));
807         break;
808
809       case ICMP_PARAMPROB:
810         proto_tree_add_text(icmp_tree, tvb, 4, 1, "Pointer: %u",
811           tvb_get_guint8(tvb, 4));
812         break;
813
814       case ICMP_REDIRECT:
815         proto_tree_add_item(icmp_tree, hf_icmp_redir_gw, tvb, 4, 4, FALSE);
816         break;
817   }
818
819   /* Decode the additional information in the packet.  */
820   switch (icmp_type) {
821       case ICMP_UNREACH:
822       case ICMP_TIMXCEED:
823       case ICMP_PARAMPROB:
824       case ICMP_SOURCEQUENCH:
825       case ICMP_REDIRECT:
826         /* Save the current value of the "we're inside an error packet"
827            flag, and set that flag; subdissectors may treat packets
828            that are the payload of error packets differently from
829            "real" packets. */
830         save_in_error_pkt = pinfo->in_error_pkt;
831         pinfo->in_error_pkt = TRUE;
832
833         /* Decode the IP header and first 64 bits of data from the
834            original datagram. */
835         next_tvb = tvb_new_subset_remaining(tvb, 8);
836
837         /* There is a collision between RFC 1812 and draft-ietf-mpls-icmp-02.
838         We don't know how to decode the 128th and following bytes of the ICMP payload.
839         According to draft-ietf-mpls-icmp-02, these bytes should be decoded as MPLS extensions
840         whereas RFC 1812 tells us to decode them as a portion of the original packet.
841         Let the user decide.
842
843         Here the user decided to favor MPLS extensions.
844         Force the IP dissector to decode only the first 128 bytes. */
845         if ((tvb_reported_length(tvb) > 8 + 128) &&
846                         favor_icmp_mpls_ext && (tvb_get_ntohs(tvb, 8 + 2) > 128))
847                 set_actual_length(next_tvb, 128);
848
849         call_dissector(ip_handle, next_tvb, pinfo, icmp_tree);
850
851         /* Restore the "we're inside an error packet" flag. */
852         pinfo->in_error_pkt = save_in_error_pkt;
853
854         /* Decode MPLS extensions if the payload has at least 128 bytes, and
855                 - the original packet in the ICMP payload has less than 128 bytes, or
856                 - the user favors the MPLS extensions analysis */
857         if ((tvb_reported_length(tvb) > 8 + 128)
858                         && (tvb_get_ntohs(tvb, 8 + 2) <= 128 || favor_icmp_mpls_ext))
859                 dissect_mpls_extensions(tvb, 8 + 128, icmp_tree);
860
861         break;
862
863       case ICMP_ECHOREPLY:
864       case ICMP_ECHO:
865         call_dissector(data_handle, tvb_new_subset_remaining(tvb, 8), pinfo,
866                        icmp_tree);
867         break;
868
869       case ICMP_RTRADVERT:
870         if (addr_entry_size == 2) {
871           for (i = 0; i < num_addrs; i++) {
872             proto_tree_add_text(icmp_tree, tvb, 8 + (i*8), 4,
873               "Router address: %s",
874               ip_to_str(tvb_get_ptr(tvb, 8 + (i*8), 4)));
875             proto_tree_add_text(icmp_tree, tvb, 12 + (i*8), 4,
876               "Preference level: %d", tvb_get_ntohl(tvb, 12 + (i*8)));
877           }
878           if ((icmp_code == 0) || (icmp_code == 16)) {
879                 /* Mobile-Ip */
880                 dissect_mip_extensions(tvb, 8 + i*8, icmp_tree);
881           }
882         } else
883           call_dissector(data_handle, tvb_new_subset_remaining(tvb, 8), pinfo,
884                          icmp_tree);
885         break;
886
887       case ICMP_TSTAMP:
888       case ICMP_TSTAMPREPLY:
889         proto_tree_add_text(icmp_tree, tvb, 8, 4, "Originate timestamp: %s after midnight UTC",
890           time_msecs_to_str(tvb_get_ntohl(tvb, 8)));
891         proto_tree_add_text(icmp_tree, tvb, 12, 4, "Receive timestamp: %s after midnight UTC",
892           time_msecs_to_str(tvb_get_ntohl(tvb, 12)));
893         proto_tree_add_text(icmp_tree, tvb, 16, 4, "Transmit timestamp: %s after midnight UTC",
894           time_msecs_to_str(tvb_get_ntohl(tvb, 16)));
895         break;
896
897     case ICMP_MASKREQ:
898     case ICMP_MASKREPLY:
899         proto_tree_add_text(icmp_tree, tvb, 8, 4, "Address mask: %s (0x%08x)",
900           ip_to_str(tvb_get_ptr(tvb, 8, 4)), tvb_get_ntohl(tvb, 8));
901         break;
902   }
903 }
904
905 void
906 proto_register_icmp(void)
907 {
908   static hf_register_info hf[] = {
909
910     { &hf_icmp_type,
911       { "Type",         "icmp.type",            FT_UINT8, BASE_DEC,     NULL, 0x0,
912         NULL, HFILL }},
913
914     { &hf_icmp_code,
915       { "Code",         "icmp.code",            FT_UINT8, BASE_DEC,     NULL, 0x0,
916         NULL, HFILL }},
917
918     { &hf_icmp_checksum,
919       { "Checksum",     "icmp.checksum",        FT_UINT16, BASE_HEX,    NULL, 0x0,
920         NULL, HFILL }},
921
922     { &hf_icmp_checksum_bad,
923       { "Bad Checksum", "icmp.checksum_bad",    FT_BOOLEAN, BASE_NONE,  NULL, 0x0,
924         NULL, HFILL }},
925
926     { &hf_icmp_ident,
927       { "Identifier", "icmp.ident",              FT_UINT16, BASE_HEX,    NULL, 0x0,
928         NULL, HFILL }},
929
930     { &hf_icmp_seq_num,
931       { "Sequence number", "icmp.seq",           FT_UINT16, BASE_DEC_HEX,    NULL, 0x0,
932         NULL, HFILL }},
933
934     { &hf_icmp_mtu,
935       { "MTU of next hop", "icmp.mtu",           FT_UINT16, BASE_DEC,    NULL, 0x0,
936         NULL, HFILL}},
937
938     { &hf_icmp_redir_gw,
939       { "Gateway address", "icmp.redir_gw",      FT_IPv4, BASE_NONE,     NULL, 0x0,
940         NULL, HFILL }},
941
942     { &hf_icmp_mip_type,
943       { "Extension Type", "icmp.mip.type",      FT_UINT8, BASE_DEC,
944         VALS(mip_extensions), 0x0,NULL, HFILL}},
945
946     { &hf_icmp_mip_length,
947       { "Length", "icmp.mip.length",            FT_UINT8, BASE_DEC, NULL, 0x0,
948         NULL, HFILL}},
949
950     { &hf_icmp_mip_prefix_length,
951       { "Prefix Length", "icmp.mip.prefixlength",  FT_UINT8, BASE_DEC, NULL, 0x0,
952         NULL, HFILL}},
953
954     { &hf_icmp_mip_seq,
955       { "Sequence Number", "icmp.mip.seq",      FT_UINT16, BASE_DEC, NULL, 0x0,
956         NULL, HFILL}},
957
958     { &hf_icmp_mip_life,
959       { "Registration Lifetime", "icmp.mip.life",  FT_UINT16, BASE_DEC, NULL, 0x0,
960         NULL, HFILL}},
961
962     { &hf_icmp_mip_flags,
963       { "Flags", "icmp.mip.flags",            FT_UINT16, BASE_HEX, NULL, 0x0,
964         NULL, HFILL}},
965
966     { &hf_icmp_mip_r,
967       { "Registration Required", "icmp.mip.r", FT_BOOLEAN, 16, NULL, 0x8000,
968         "Registration with this FA is required", HFILL }},
969
970     { &hf_icmp_mip_b,
971       { "Busy", "icmp.mip.b", FT_BOOLEAN, 16, NULL, 0x4000,
972         "This FA will not accept requests at this time", HFILL }},
973
974     { &hf_icmp_mip_h,
975       { "Home Agent", "icmp.mip.h", FT_BOOLEAN, 16, NULL, 0x2000,
976         "Home Agent Services Offered", HFILL }},
977
978     { &hf_icmp_mip_f,
979       { "Foreign Agent", "icmp.mip.f", FT_BOOLEAN, 16, NULL, 0x1000,
980         "Foreign Agent Services Offered", HFILL }},
981
982     { &hf_icmp_mip_m,
983       { "Minimal Encapsulation", "icmp.mip.m", FT_BOOLEAN, 16, NULL, 0x0800,
984         "Minimal encapsulation tunneled datagram support", HFILL }},
985
986     { &hf_icmp_mip_g,
987       { "GRE", "icmp.mip.g", FT_BOOLEAN, 16, NULL, 0x0400,
988         "GRE encapsulated tunneled datagram support", HFILL }},
989
990     { &hf_icmp_mip_v,
991       { "VJ Comp", "icmp.mip.v", FT_BOOLEAN, 16, NULL, 0x0200,
992         "Van Jacobson Header Compression Support", HFILL }},
993
994     { &hf_icmp_mip_rt,
995       { "Reverse tunneling", "icmp.mip.rt", FT_BOOLEAN, 16, NULL, 0x0100,
996        "Reverse tunneling support", HFILL }},
997
998     { &hf_icmp_mip_u,
999       { "UDP tunneling", "icmp.mip.u", FT_BOOLEAN, 16, NULL, 0x0080,
1000        "UDP tunneling support", HFILL }},
1001
1002     { &hf_icmp_mip_x,
1003       { "Revocation support", "icmp.mip.x", FT_BOOLEAN, 16, NULL, 0x0040,
1004        "Registration revocation support", HFILL }},
1005
1006
1007     { &hf_icmp_mip_reserved,
1008       { "Reserved", "icmp.mip.reserved",     FT_UINT16, BASE_HEX, NULL, 0x003f,
1009         NULL, HFILL}},
1010
1011     { &hf_icmp_mip_coa,
1012       { "Care-Of-Address", "icmp.mip.coa",    FT_IPv4, BASE_NONE, NULL, 0x0,
1013         NULL, HFILL}},
1014
1015     { &hf_icmp_mip_challenge,
1016       { "Challenge", "icmp.mip.challenge",    FT_BYTES, BASE_NONE, NULL, 0x0,
1017         NULL, HFILL}},
1018
1019     { &hf_icmp_mpls,
1020       { "ICMP Extensions for MPLS",     "icmp.mpls",    FT_NONE, BASE_NONE,     NULL, 0x0,
1021         NULL, HFILL }},
1022
1023     { &hf_icmp_mpls_version,
1024       { "Version",              "icmp.mpls.version", FT_UINT8, BASE_DEC, NULL, 0x0,
1025         NULL, HFILL }},
1026
1027     { &hf_icmp_mpls_reserved,
1028       { "Reserved",     "icmp.mpls.res",        FT_UINT16, BASE_HEX,    NULL, 0x0,
1029         NULL, HFILL }},
1030
1031     { &hf_icmp_mpls_checksum,
1032       { "Checksum",     "icmp.mpls.checksum",   FT_UINT16, BASE_HEX,    NULL, 0x0,
1033         NULL, HFILL }},
1034
1035     { &hf_icmp_mpls_checksum_bad,
1036       { "Bad Checksum", "icmp.mpls.checksum_bad",       FT_BOOLEAN, BASE_NONE,  NULL, 0x0,
1037         NULL, HFILL }},
1038
1039     { &hf_icmp_mpls_length,
1040       { "Length",       "icmp.mpls.length",     FT_UINT16, BASE_HEX,    NULL, 0x0,
1041         NULL, HFILL }},
1042
1043     { &hf_icmp_mpls_class,
1044       { "Class",        "icmp.mpls.class", FT_UINT8, BASE_DEC, NULL, 0x0,
1045         NULL, HFILL }},
1046
1047     { &hf_icmp_mpls_c_type,
1048       { "C-Type",       "icmp.mpls.ctype", FT_UINT8, BASE_DEC, NULL, 0x0,
1049         NULL, HFILL }},
1050
1051     { &hf_icmp_mpls_label,
1052       { "Label",        "icmp.mpls.label", FT_UINT24, BASE_DEC, NULL, 0x00fffff0,
1053         NULL, HFILL }},
1054
1055     { &hf_icmp_mpls_exp,
1056       { "Experimental", "icmp.mpls.exp", FT_UINT24, BASE_DEC, NULL, 0x0e,
1057         NULL, HFILL }},
1058
1059     { &hf_icmp_mpls_s,
1060       { "Stack bit",    "icmp.mpls.s", FT_BOOLEAN, 24, TFS(&tfs_set_notset), 0x01,
1061         NULL, HFILL }},
1062
1063     { &hf_icmp_mpls_ttl,
1064       { "Time to live", "icmp.mpls.ttl", FT_UINT8, BASE_DEC, NULL, 0x0,
1065         NULL, HFILL }}
1066   };
1067
1068   static gint *ett[] = {
1069     &ett_icmp,
1070     &ett_icmp_mip,
1071     &ett_icmp_mip_flags,
1072     /* MPLS extensions */
1073     &ett_icmp_mpls,
1074     &ett_icmp_mpls_object,
1075     &ett_icmp_mpls_stack_object
1076   };
1077
1078   module_t *icmp_module;
1079
1080   proto_icmp = proto_register_protocol("Internet Control Message Protocol",
1081                                        "ICMP", "icmp");
1082   proto_register_field_array(proto_icmp, hf, array_length(hf));
1083   proto_register_subtree_array(ett, array_length(ett));
1084
1085   icmp_module = prefs_register_protocol(proto_icmp, NULL);
1086
1087   prefs_register_bool_preference(icmp_module, "favor_icmp_mpls",
1088             "Favor ICMP extensions for MPLS",
1089             "Whether the 128th and following bytes of the ICMP payload should be decoded as MPLS extensions or as a portion of the original packet",
1090             &favor_icmp_mpls_ext);
1091
1092   register_dissector("icmp", dissect_icmp, proto_icmp);
1093 }
1094
1095 void
1096 proto_reg_handoff_icmp(void)
1097 {
1098   dissector_handle_t icmp_handle;
1099
1100   /*
1101    * Get handle for the IP dissector.
1102    */
1103   ip_handle = find_dissector("ip");
1104   icmp_handle = find_dissector("icmp");
1105   data_handle = find_dissector("data");
1106
1107   dissector_add("ip.proto", IP_PROTO_ICMP, icmp_handle);
1108 }