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