I removed the bit-fields that depended upon gcc's ability to use any type
[obnox/wireshark/wip.git] / packet-ip.c
1 /* packet-ip.c
2  * Routines for IP and miscellaneous IP protocol packet disassembly
3  *
4  * $Id: packet-ip.c,v 1.14 1999/02/08 20:02:34 gram Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@zing.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * 
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <gtk/gtk.h>
31
32 #include <stdio.h>
33
34 #ifdef HAVE_SYS_TYPES_H
35 # include <sys/types.h>
36 #endif
37
38 #ifdef HAVE_NETINET_IN_H
39 # include <netinet/in.h>
40 #endif
41
42 #include "ethereal.h"
43 #include "packet.h"
44 #include "etypes.h"
45 #include "resolv.h"
46 #include "util.h"
47
48 extern packet_info pi;
49
50 static void
51 dissect_ipopt_security(GtkWidget *opt_tree, const char *name,
52     const u_char *opd, int offset, guint optlen)
53 {
54   GtkWidget *field_tree = NULL, *tf;
55   guint      val;
56   static const value_string secl_vals[] = {
57     {IPSEC_UNCLASSIFIED, "Unclassified"},
58     {IPSEC_CONFIDENTIAL, "Confidential"},
59     {IPSEC_EFTO,         "EFTO"        },
60     {IPSEC_MMMM,         "MMMM"        },
61     {IPSEC_RESTRICTED,   "Restricted"  },
62     {IPSEC_SECRET,       "Secret"      },
63     {IPSEC_TOPSECRET,    "Top secret"  },
64     {IPSEC_RESERVED1,    "Reserved"    },
65     {IPSEC_RESERVED2,    "Reserved"    },
66     {IPSEC_RESERVED3,    "Reserved"    },
67     {IPSEC_RESERVED4,    "Reserved"    },
68     {IPSEC_RESERVED5,    "Reserved"    },
69     {IPSEC_RESERVED6,    "Reserved"    },
70     {IPSEC_RESERVED7,    "Reserved"    },
71     {IPSEC_RESERVED8,    "Reserved"    },
72     {0,                  NULL          } };
73
74   tf = add_item_to_tree(opt_tree, offset,      optlen, "%s:", name);
75   field_tree = gtk_tree_new();
76   add_subtree(tf, field_tree, ETT_IP_OPTION_SEC);
77   offset += 2;
78
79   val = pntohs(opd);
80   add_item_to_tree(field_tree, offset,       2,
81               "Security: %s", val_to_str(val, secl_vals, "Unknown (0x%x)"));
82   offset += 2;
83   opd += 2;
84
85   val = pntohs(opd);
86   add_item_to_tree(field_tree, offset,         2,
87               "Compartments: %d", val);
88   offset += 2;
89   opd += 2;
90
91   add_item_to_tree(field_tree, offset,         2,
92               "Handling restrictions: %c%c", opd[0], opd[1]);
93   offset += 2;
94   opd += 2;
95
96   add_item_to_tree(field_tree, offset,         3,
97               "Transmission control code: %c%c%c", opd[0], opd[1], opd[2]);
98 }
99
100 static void
101 dissect_ipopt_route(GtkWidget *opt_tree, const char *name,
102     const u_char *opd, int offset, guint optlen)
103 {
104   GtkWidget *field_tree = NULL, *tf;
105   int ptr;
106   int optoffset = 0;
107   struct in_addr addr;
108
109   tf = add_item_to_tree(opt_tree, offset,      optlen, "%s (%d bytes)", name,
110               optlen);
111   field_tree = gtk_tree_new();
112   add_subtree(tf, field_tree, ETT_IP_OPTION_ROUTE);
113
114   optoffset += 2;       /* skip past type and length */
115   optlen -= 2;          /* subtract size of type and length */
116
117   ptr = *opd;
118   add_item_to_tree(field_tree, offset + optoffset, 1,
119               "Pointer: %d%s", ptr,
120               ((ptr < 4) ? " (points before first address)" :
121                ((ptr & 3) ? " (points to middle of address)" : "")));
122   optoffset++;
123   opd++;
124   optlen--;
125   ptr--;        /* ptr is 1-origin */
126
127   while (optlen > 0) {
128     if (optlen < 4) {
129       add_item_to_tree(field_tree, offset,      optlen,
130         "(suboption would go past end of option)");
131       break;
132     }
133
134     /* Avoids alignment problems on many architectures. */
135     memcpy((char *)&addr, (char *)opd, sizeof(addr));
136
137     add_item_to_tree(field_tree, offset + optoffset, 4,
138               "%s%s",
139               ((addr.s_addr == 0) ? "-" : (char *)get_hostname(addr.s_addr)),
140               ((optoffset == ptr) ? " <- (current)" : ""));
141     optoffset += 4;
142     opd += 4;
143     optlen -= 4;
144   }
145 }
146
147 static void
148 dissect_ipopt_sid(GtkWidget *opt_tree, const char *name, const u_char *opd,
149     int offset, guint optlen)
150 {
151   add_item_to_tree(opt_tree, offset,      optlen,
152     "%s: %d", name, pntohs(opd));
153   return;
154 }
155
156 static void
157 dissect_ipopt_timestamp(GtkWidget *opt_tree, const char *name, const u_char *opd,
158     int offset, guint optlen)
159 {
160   GtkWidget *field_tree = NULL, *tf;
161   int        ptr;
162   int        optoffset = 0;
163   int        flg;
164   static const value_string flag_vals[] = {
165     {IPOPT_TS_TSONLY,    "Time stamps only"                      },
166     {IPOPT_TS_TSANDADDR, "Time stamp and address"                },
167     {IPOPT_TS_PRESPEC,   "Time stamps for prespecified addresses"},
168     {0,                  NULL                                    } };
169
170   struct in_addr addr;
171   guint ts;
172
173   tf = add_item_to_tree(opt_tree, offset,      optlen, "%s:", name);
174   field_tree = gtk_tree_new();
175   add_subtree(tf, field_tree, ETT_IP_OPTION_TIMESTAMP);
176
177   optoffset += 2;       /* skip past type and length */
178   optlen -= 2;          /* subtract size of type and length */
179
180   ptr = *opd;
181   add_item_to_tree(field_tree, offset + optoffset, 1,
182               "Pointer: %d%s", ptr,
183               ((ptr < 5) ? " (points before first address)" :
184                (((ptr - 1) & 3) ? " (points to middle of address)" : "")));
185   optoffset++;
186   opd++;
187   optlen--;
188   ptr--;        /* ptr is 1-origin */
189
190   flg = *opd;
191   add_item_to_tree(field_tree, offset + optoffset,   1,
192         "Overflow: %d", flg >> 4);
193   flg &= 0xF;
194   add_item_to_tree(field_tree, offset + optoffset, 1,
195         "Flag: %s", val_to_str(flg, flag_vals, "Unknown (0x%x)"));
196   optoffset++;
197   opd++;
198   optlen--;
199
200   while (optlen > 0) {
201     if (flg == IPOPT_TS_TSANDADDR) {
202       if (optlen < 4) {
203         add_item_to_tree(field_tree, offset + optoffset, optlen,
204           "(suboption would go past end of option)");
205         break;
206       }
207       /* XXX - check whether it goes past end of packet */
208       ts = pntohl(opd);
209       opd += 4;
210       optlen -= 4;
211       if (optlen < 4) {
212         add_item_to_tree(field_tree, offset + optoffset, optlen,
213           "(suboption would go past end of option)");
214         break;
215       }
216       /* XXX - check whether it goes past end of packet */
217       memcpy((char *)&addr, (char *)opd, sizeof(addr));
218       opd += 4;
219       optlen -= 4;
220       add_item_to_tree(field_tree, offset,      8,
221           "Address = %s, time stamp = %u",
222           ((addr.s_addr == 0) ? "-" :  (char *)get_hostname(addr.s_addr)),
223           ts);
224       optoffset += 8;
225     } else {
226       if (optlen < 4) {
227         add_item_to_tree(field_tree, offset + optoffset, optlen,
228           "(suboption would go past end of option)");
229         break;
230       }
231       /* XXX - check whether it goes past end of packet */
232       ts = pntohl(opd);
233       opd += 4;
234       optlen -= 4;
235       add_item_to_tree(field_tree, offset + optoffset, 4,
236           "Time stamp = %u", ts);
237       optoffset += 4;
238     }
239   }
240 }
241
242 static ip_tcp_opt ipopts[] = {
243   {
244     IPOPT_END,
245     "EOL",
246     NO_LENGTH,
247     0,
248     NULL,
249   },
250   {
251     IPOPT_NOOP,
252     "NOP",
253     NO_LENGTH,
254     0,
255     NULL,
256   },
257   {
258     IPOPT_SEC,
259     "Security",
260     FIXED_LENGTH,
261     IPOLEN_SEC,
262     dissect_ipopt_security
263   },
264   {
265     IPOPT_SSRR,
266     "Strict source route",
267     VARIABLE_LENGTH,
268     IPOLEN_SSRR_MIN,
269     dissect_ipopt_route
270   },
271   {
272     IPOPT_LSRR,
273     "Loose source route",
274     VARIABLE_LENGTH,
275     IPOLEN_LSRR_MIN,
276     dissect_ipopt_route
277   },
278   {
279     IPOPT_RR,
280     "Record route",
281     VARIABLE_LENGTH,
282     IPOLEN_RR_MIN,
283     dissect_ipopt_route
284   },
285   {
286     IPOPT_SID,
287     "Stream identifier",
288     FIXED_LENGTH,
289     IPOLEN_SID,
290     dissect_ipopt_sid
291   },
292   {
293     IPOPT_TIMESTAMP,
294     "Time stamp",
295     VARIABLE_LENGTH,
296     IPOLEN_TIMESTAMP_MIN,
297     dissect_ipopt_timestamp
298   }
299 };
300
301 #define N_IP_OPTS       (sizeof ipopts / sizeof ipopts[0])
302
303 /* Dissect the IP or TCP options in a packet. */
304 void
305 dissect_ip_tcp_options(GtkWidget *opt_tree, const u_char *opd, int offset,
306     guint length, ip_tcp_opt *opttab, int nopts, int eol)
307 {
308   u_char      opt;
309   ip_tcp_opt *optp;
310   guint       len;
311
312   while (length > 0) {
313     opt = *opd++;
314     for (optp = &opttab[0]; optp < &opttab[nopts]; optp++) {
315       if (optp->optcode == opt)
316         break;
317     }
318     if (optp == &opttab[nopts]) {
319       add_item_to_tree(opt_tree, offset,      1, "Unknown");
320       /* We don't know how long this option is, so we don't know how much
321          of it to skip, so we just bail. */
322       return;
323     }
324     --length;      /* account for type byte */
325     if (optp->len_type != NO_LENGTH) {
326       /* Option has a length. Is it in the packet? */
327       if (length == 0) {
328         /* Bogus - packet must at least include option code byte and
329            length byte! */
330         add_item_to_tree(opt_tree, offset,      1,
331               "%s (length byte past end of header)", optp->name);
332         return;
333       }
334       len = *opd++;  /* total including type, len */
335       --length;    /* account for length byte */
336       if (len < 2) {
337         /* Bogus - option length is too short to include option code and
338            option length. */
339         add_item_to_tree(opt_tree, offset,      2,
340               "%s (with too-short option length = %u bytes)", optp->name, 2);
341         return;
342       } else if (len - 2 > length) {
343         /* Bogus - option goes past the end of the header. */
344         add_item_to_tree(opt_tree, offset,      length,
345               "%s (option goes past end of header)", optp->name);
346         return;
347       } else if (optp->len_type == FIXED_LENGTH && len != optp->optlen) {
348         /* Bogus - option length isn't what it's supposed to be for this
349            option. */
350         add_item_to_tree(opt_tree, offset,      len,
351               "%s (with option length = %u bytes; should be %u)", optp->name,
352               len, optp->optlen);
353         return;
354       } else if (optp->len_type == VARIABLE_LENGTH && len < optp->optlen) {
355         /* Bogus - option length is less than what it's supposed to be for
356            this option. */
357         add_item_to_tree(opt_tree, offset,      len,
358               "%s (with option length = %u bytes; should be >= %u)", optp->name,
359               len, optp->optlen);
360         return;
361       } else {
362         if (optp->dissect != NULL) {
363           /* Option has a dissector. */
364           (*optp->dissect)(opt_tree, optp->name, opd, offset, len);
365         } else {
366           /* Option has no data, hence no dissector. */
367           add_item_to_tree(opt_tree, offset,      len, "%s", optp->name);
368         }
369         len -= 2;       /* subtract size of type and length */
370         offset += 2 + len;
371       }
372       opd += len;
373       length -= len;
374     } else {
375       add_item_to_tree(opt_tree, offset,      1, "%s", optp->name);
376       offset += 1;
377     }
378     if (opt == eol)
379       break;
380   }
381 }
382
383 void
384 dissect_ip(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) {
385   e_ip       iph;
386   GtkWidget *ip_tree, *ti, *field_tree, *tf;
387   gchar      tos_str[32];
388   guint      hlen, optlen;
389   static const value_string proto_vals[] = { {IP_PROTO_ICMP, "ICMP"},
390                                              {IP_PROTO_IGMP, "IGMP"},
391                                              {IP_PROTO_TCP,  "TCP" },
392                                              {IP_PROTO_UDP,  "UDP" },
393                                              {IP_PROTO_OSPF, "OSPF"},
394                                              {0,             NULL  } };
395   static const value_string precedence_vals[] = {
396                   { IPTOS_PREC_ROUTINE,         "routine"              },
397                   { IPTOS_PREC_PRIORITY,        "priority"             },
398                   { IPTOS_PREC_IMMEDIATE,       "immediate"            },
399                   { IPTOS_PREC_FLASH,           "flash"                },
400                   { IPTOS_PREC_FLASHOVERRIDE,   "flash override"       },
401                   { IPTOS_PREC_CRITIC_ECP,      "CRITIC/ECP"           },
402                   { IPTOS_PREC_INTERNETCONTROL, "internetwork control" },
403                   { IPTOS_PREC_NETCONTROL,      "network control"      },
404                   { 0,                          NULL                   } };
405
406   /* To do: check for runts, errs, etc. */
407   /* Avoids alignment problems on many architectures. */
408   memcpy(&iph, &pd[offset], sizeof(e_ip));
409   iph.ip_len = ntohs(iph.ip_len);
410   iph.ip_id  = ntohs(iph.ip_id);
411   iph.ip_off = ntohs(iph.ip_off);
412   iph.ip_sum = ntohs(iph.ip_sum);
413
414   hlen = lo_nibble(iph.ip_v_hl) * 4;    /* IP header length, in bytes */
415   
416   switch (iph.ip_p) {
417     case IP_PROTO_ICMP:
418     case IP_PROTO_IGMP:
419     case IP_PROTO_TCP:
420     case IP_PROTO_UDP:
421     case IP_PROTO_OSPF:
422       /* Names are set in the associated dissect_* routines */
423       break;
424     default:
425       if (check_col(fd, COL_PROTOCOL))
426         col_add_str(fd, COL_PROTOCOL, "IP");
427       if (check_col(fd, COL_INFO))
428         col_add_fstr(fd, COL_INFO, "Unknown IP protocol (%02x)", iph.ip_p);
429   }
430
431   if (check_col(fd, COL_RES_NET_SRC))
432     col_add_str(fd, COL_RES_NET_SRC, get_hostname(iph.ip_src));
433   if (check_col(fd, COL_UNRES_NET_SRC))
434     col_add_str(fd, COL_UNRES_NET_SRC, ip_to_str((guint8 *) &iph.ip_src));
435   if (check_col(fd, COL_RES_NET_DST))
436     col_add_str(fd, COL_RES_NET_DST, get_hostname(iph.ip_dst));
437   if (check_col(fd, COL_UNRES_NET_DST))
438     col_add_str(fd, COL_UNRES_NET_DST, ip_to_str((guint8 *) &iph.ip_dst));
439   
440   iph.ip_tos = IPTOS_TOS(iph.ip_tos);
441   switch (iph.ip_tos) {
442     case IPTOS_NONE:
443       strcpy(tos_str, "None");
444       break;
445     case IPTOS_LOWCOST:
446       strcpy(tos_str, "Minimize cost");
447       break;
448     case IPTOS_RELIABILITY:
449       strcpy(tos_str, "Maximize reliability");
450       break;
451     case IPTOS_THROUGHPUT:
452       strcpy(tos_str, "Maximize throughput");
453       break;
454     case IPTOS_LOWDELAY:
455       strcpy(tos_str, "Minimize delay");
456       break;
457     case IPTOS_SECURITY:
458       strcpy(tos_str, "Maximize security");
459       break;
460     default:
461       strcpy(tos_str, "Unknown.  Malformed?");
462       break;
463   }
464   
465   if (tree) {
466     ti = add_item_to_tree(GTK_WIDGET(tree), offset, hlen, "Internet Protocol");
467     ip_tree = gtk_tree_new();
468     add_subtree(ti, ip_tree, ETT_IP);
469     add_item_to_tree(ip_tree, offset,      1, "Version: %d", hi_nibble(iph.ip_v_hl));
470     add_item_to_tree(ip_tree, offset,      1, "Header length: %d bytes", hlen); 
471     tf = add_item_to_tree(ip_tree, offset +  1, 1, "Type of service: 0x%02x (%s)",
472       iph.ip_tos, tos_str);
473     field_tree = gtk_tree_new();
474     add_subtree(tf, field_tree, ETT_IP_TOS);
475     add_item_to_tree(field_tree, offset + 1, 1, "%s",
476        decode_enumerated_bitfield(iph.ip_tos, IPTOS_PREC_MASK,
477                                    sizeof (iph.ip_tos)*8, precedence_vals,
478                                    "%s precedence"));
479     add_item_to_tree(field_tree, offset + 1, 1, "%s",
480        decode_boolean_bitfield(iph.ip_tos, IPTOS_LOWDELAY,
481                 sizeof (iph.ip_tos)*8, "low delay", "normal delay"));
482     add_item_to_tree(field_tree, offset + 1, 1, "%s",
483        decode_boolean_bitfield(iph.ip_tos, IPTOS_THROUGHPUT,
484             sizeof (iph.ip_tos)*8, "high throughput", "normal throughput"));
485     add_item_to_tree(field_tree, offset + 1, 1, "%s",
486        decode_boolean_bitfield(iph.ip_tos, IPTOS_RELIABILITY,
487             sizeof (iph.ip_tos)*8, "high reliability", "normal reliability"));
488     add_item_to_tree(field_tree, offset + 1, 1, "%s",
489        decode_boolean_bitfield(iph.ip_tos, IPTOS_LOWCOST,
490             sizeof (iph.ip_tos)*8, "low cost", "normal cost"));
491     add_item_to_tree(ip_tree, offset +  2, 2, "Total length: %d", iph.ip_len);
492     add_item_to_tree(ip_tree, offset +  4, 2, "Identification: 0x%04x",
493       iph.ip_id);
494     tf = add_item_to_tree(ip_tree, offset +  6, 2, "Flags: 0x%x",
495       (iph.ip_off & (IP_DF|IP_MF)) >> 12);
496     field_tree = gtk_tree_new();
497     add_subtree(tf, field_tree, ETT_IP_OFF);
498     add_item_to_tree(field_tree, offset + 6, 2, "%s",
499       decode_boolean_bitfield(iph.ip_off >> 8, IP_DF >> 8, 8, "don't fragment",
500                                            "may fragment"));
501     add_item_to_tree(field_tree, offset + 6, 2, "%s",
502       decode_boolean_bitfield(iph.ip_off >> 8, IP_MF >> 8, 8, "more fragments",
503                                            "last fragment"));
504     add_item_to_tree(ip_tree, offset +  6, 2, "Fragment offset: %d",
505       iph.ip_off & IP_OFFSET);
506     add_item_to_tree(ip_tree, offset +  8, 1, "Time to live: %d",
507       iph.ip_ttl);
508     add_item_to_tree(ip_tree, offset +  9, 1, "Protocol: %s",
509       val_to_str(iph.ip_p, proto_vals, "Unknown (%x)"));
510     add_item_to_tree(ip_tree, offset + 10, 2, "Header checksum: 0x%04x",
511       iph.ip_sum);
512     add_item_to_tree(ip_tree, offset + 12, 4, "Source address: %s (%s)",
513                      get_hostname(iph.ip_src),
514                      ip_to_str((guint8 *) &iph.ip_src));
515     add_item_to_tree(ip_tree, offset + 16, 4, "Destination address: %s (%s)",
516                      get_hostname(iph.ip_dst),
517                      ip_to_str((guint8 *) &iph.ip_dst));
518
519     /* Decode IP options, if any. */
520     if (hlen > sizeof (e_ip)) {
521       /* There's more than just the fixed-length header.  Decode the
522          options. */
523       optlen = hlen - sizeof (e_ip);    /* length of options, in bytes */
524       tf = add_item_to_tree(ip_tree, offset +  20, optlen,
525         "Options: (%d bytes)", optlen);
526       field_tree = gtk_tree_new();
527       add_subtree(tf, field_tree, ETT_IP_OPTIONS);
528       dissect_ip_tcp_options(field_tree, &pd[offset + 20], offset + 20, optlen,
529          ipopts, N_IP_OPTS, IPOPT_END);
530     }
531   }
532
533   pi.srcip = ip_to_str( (guint8 *) &iph.ip_src);
534   pi.destip = ip_to_str( (guint8 *) &iph.ip_dst);
535   pi.ipproto = iph.ip_p;
536   pi.iplen = iph.ip_len;
537   pi.iphdrlen = lo_nibble(iph.ip_v_hl);
538   pi.ip_src = iph.ip_src;
539
540   offset += hlen;
541   switch (iph.ip_p) {
542     case IP_PROTO_ICMP:
543       dissect_icmp(pd, offset, fd, tree);
544      break;
545     case IP_PROTO_IGMP:
546       dissect_igmp(pd, offset, fd, tree);
547      break;
548     case IP_PROTO_TCP:
549       dissect_tcp(pd, offset, fd, tree);
550      break;
551    case IP_PROTO_UDP:
552       dissect_udp(pd, offset, fd, tree);
553       break;
554     case IP_PROTO_OSPF:
555       dissect_ospf(pd, offset, fd, tree);
556      break;
557   }
558 }
559
560
561 const gchar *unreach_str[] = {"Network unreachable",
562                               "Host unreachable",
563                               "Protocol unreachable",
564                               "Port unreachable",
565                               "Fragmentation needed",
566                               "Source route failed",
567                               "Administratively prohibited",
568                               "Network unreachable for TOS",
569                               "Host unreachable for TOS",
570                               "Communication administratively filtered",
571                               "Host precedence violation",
572                               "Precedence cutoff in effect"};
573
574 const gchar *redir_str[] = {"Redirect for network",
575                             "Redirect for host",
576                             "Redirect for TOS and network",
577                             "Redirect for TOS and host"};
578
579 const gchar *ttl_str[] = {"TTL equals 0 during transit",
580                           "TTL equals 0 during reassembly"};
581
582 const gchar *par_str[] = {"IP header bad", "Required option missing"};
583
584 void
585 dissect_icmp(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) {
586   e_icmp     ih;
587   GtkWidget *icmp_tree, *ti;
588   guint16    cksum;
589   gchar      type_str[64], code_str[64] = "";
590
591   /* Avoids alignment problems on many architectures. */
592   memcpy(&ih, &pd[offset], sizeof(e_icmp));
593   /* To do: check for runts, errs, etc. */
594   cksum = ntohs(ih.icmp_cksum);
595   
596   switch (ih.icmp_type) {
597     case ICMP_ECHOREPLY:
598       strcpy(type_str, "Echo (ping) reply");
599       break;
600     case ICMP_UNREACH:
601       strcpy(type_str, "Destination unreachable");
602       if (ih.icmp_code < 12) {
603         sprintf(code_str, "(%s)", unreach_str[ih.icmp_code]);
604       } else {
605         strcpy(code_str, "(Unknown - error?)");
606       }
607       break;
608     case ICMP_SOURCEQUENCH:
609       strcpy(type_str, "Source quench (flow control)");
610       break;
611     case ICMP_REDIRECT:
612       strcpy(type_str, "Redirect");
613       if (ih.icmp_code < 4) {
614         sprintf(code_str, "(%s)", redir_str[ih.icmp_code]);
615       } else {
616         strcpy(code_str, "(Unknown - error?)");
617       }
618       break;
619     case ICMP_ECHO:
620       strcpy(type_str, "Echo (ping) request");
621       break;
622     case ICMP_TIMXCEED:
623       strcpy(type_str, "Time-to-live exceeded");
624       if (ih.icmp_code < 2) {
625         sprintf(code_str, "(%s)", ttl_str[ih.icmp_code]);
626       } else {
627         strcpy(code_str, "(Unknown - error?)");
628       }
629       break;
630     case ICMP_PARAMPROB:
631       strcpy(type_str, "Parameter problem");
632       if (ih.icmp_code < 2) {
633         sprintf(code_str, "(%s)", par_str[ih.icmp_code]);
634       } else {
635         strcpy(code_str, "(Unknown - error?)");
636       }
637       break;
638     case ICMP_TSTAMP:
639       strcpy(type_str, "Timestamp request");
640       break;
641     case ICMP_TSTAMPREPLY:
642       strcpy(type_str, "Timestamp reply");
643       break;
644     case ICMP_MASKREQ:
645       strcpy(type_str, "Address mask request");
646       break;
647     case ICMP_MASKREPLY:
648       strcpy(type_str, "Address mask reply");
649       break;
650     default:
651       strcpy(type_str, "Unknown ICMP (obsolete or malformed?)");
652   }
653
654   if (check_col(fd, COL_PROTOCOL))
655     col_add_str(fd, COL_PROTOCOL, "ICMP");
656   if (check_col(fd, COL_INFO))
657     col_add_str(fd, COL_INFO, type_str);
658   
659   if (tree) {
660     ti = add_item_to_tree(GTK_WIDGET(tree), offset, 4,
661       "Internet Control Message Protocol");
662     icmp_tree = gtk_tree_new();
663     add_subtree(ti, icmp_tree, ETT_ICMP);
664     add_item_to_tree(icmp_tree, offset,      1, "Type: %d (%s)",
665       ih.icmp_type, type_str);
666     add_item_to_tree(icmp_tree, offset +  1, 1, "Code: %d %s",
667       ih.icmp_code, code_str);
668     add_item_to_tree(icmp_tree, offset +  2, 2, "Checksum: 0x%04x",
669       ih.icmp_cksum);
670   }
671 }
672
673 void
674 dissect_igmp(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) {
675   e_igmp     ih;
676   GtkWidget *igmp_tree, *ti;
677   guint16    cksum;
678   gchar      type_str[64] = "";
679
680   /* Avoids alignment problems on many architectures. */
681   memcpy(&ih, &pd[offset], sizeof(e_igmp));
682   /* To do: check for runts, errs, etc. */
683   cksum = ntohs(ih.igmp_cksum);
684   
685   switch (lo_nibble(ih.igmp_v_t)) {
686     case IGMP_M_QRY:
687       strcpy(type_str, "Router query");
688       break;
689     case IGMP_V1_M_RPT:
690       strcpy(type_str, "Host response (v1)");
691       break;
692     case IGMP_V2_LV_GRP:
693       strcpy(type_str, "Leave group (v2)");
694       break;
695     case IGMP_DVMRP:
696       strcpy(type_str, "DVMRP");
697       break;
698     case IGMP_PIM:
699       strcpy(type_str, "PIM");
700       break;
701     case IGMP_V2_M_RPT:
702       strcpy(type_str, "Host reponse (v2)");
703       break;
704     case IGMP_MTRC_RESP:
705       strcpy(type_str, "Traceroute response");
706       break;
707     case IGMP_MTRC:
708       strcpy(type_str, "Traceroute message");
709       break;
710     default:
711       strcpy(type_str, "Unknown IGMP");
712   }
713
714   if (check_col(fd, COL_PROTOCOL))
715     col_add_str(fd, COL_PROTOCOL, "IGMP");
716   if (check_col(fd, COL_INFO))
717     col_add_str(fd, COL_INFO, type_str);
718   
719   if (tree) {
720     ti = add_item_to_tree(GTK_WIDGET(tree), offset, 4,
721       "Internet Group Management Protocol");
722     igmp_tree = gtk_tree_new();
723     add_subtree(ti, igmp_tree, ETT_IGMP);
724     add_item_to_tree(igmp_tree, offset,     1, "Version: %d",
725       hi_nibble(ih.igmp_v_t));
726     add_item_to_tree(igmp_tree, offset    , 1, "Type: %d (%s)",
727       lo_nibble(ih.igmp_v_t), type_str);
728     add_item_to_tree(igmp_tree, offset + 1, 1, "Unused: 0x%02x",
729       ih.igmp_unused);
730     add_item_to_tree(igmp_tree, offset + 2, 2, "Checksum: 0x%04x",
731       ih.igmp_cksum);
732     add_item_to_tree(igmp_tree, offset + 4, 4, "Group address: %s",
733       ip_to_str((guint8 *) &ih.igmp_gaddr));
734   }
735 }