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