Stuart Stanley's ISIS dissection support.
[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.67 1999/12/13 05:09:05 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 #ifdef HAVE_SYS_TYPES_H
31 # include <sys/types.h>
32 #endif
33
34 #ifdef HAVE_NETINET_IN_H
35 # include <netinet/in.h>
36 #endif
37
38 #include <stdio.h>
39 #include <string.h>
40 #include <glib.h>
41 #include "packet.h"
42 #include "resolv.h"
43 #include "util.h"
44
45 #ifdef NEED_SNPRINTF_H
46 # ifdef HAVE_STDARG_H
47 #  include <stdarg.h>
48 # else
49 #  include <varargs.h>
50 # endif
51 # include "snprintf.h"
52 #endif
53
54 #ifndef __PACKET_IP_H__
55 #include "packet-ip.h"
56 #endif
57
58 static int proto_ip = -1;
59 static int hf_ip_version = -1;
60 static int hf_ip_hdr_len = -1;
61 static int hf_ip_tos = -1;
62 static int hf_ip_tos_precedence = -1;
63 static int hf_ip_tos_delay = -1;
64 static int hf_ip_tos_throughput = -1;
65 static int hf_ip_tos_reliability = -1;
66 static int hf_ip_tos_cost = -1;
67 static int hf_ip_len = -1;
68 static int hf_ip_id = -1;
69 static int hf_ip_dst = -1;
70 static int hf_ip_src = -1;
71 static int hf_ip_addr = -1;
72 static int hf_ip_flags = -1;
73 static int hf_ip_flags_df = -1;
74 static int hf_ip_flags_mf = -1;
75 static int hf_ip_frag_offset = -1;
76 static int hf_ip_ttl = -1;
77 static int hf_ip_proto = -1;
78 static int hf_ip_checksum = -1;
79
80 static gint ett_ip = -1;
81 static gint ett_ip_tos = -1;
82 static gint ett_ip_off = -1;
83 static gint ett_ip_options = -1;
84 static gint ett_ip_option_sec = -1;
85 static gint ett_ip_option_route = -1;
86 static gint ett_ip_option_timestamp = -1;
87
88 static int proto_igmp = -1;
89 static int hf_igmp_version = -1;
90 static int hf_igmp_type = -1;
91 static int hf_igmp_unused = -1;
92 static int hf_igmp_checksum = -1;
93 static int hf_igmp_group = -1;
94
95 static gint ett_igmp = -1;
96
97 static int proto_icmp = -1;
98 static int hf_icmp_type = -1;
99 static int hf_icmp_code = -1;
100 static int hf_icmp_checksum = -1;
101
102 static gint ett_icmp = -1;
103
104 /* ICMP structs and definitions */
105 typedef struct _e_icmp {
106   guint8  icmp_type;
107   guint8  icmp_code;
108   guint16 icmp_cksum;
109   union {
110     struct {  /* Address mask request/reply */
111       guint16 id;
112       guint16 seq;
113       guint32 sn_mask;
114     } am;
115     struct {  /* Timestap request/reply */
116       guint16 id;
117       guint16 seq;
118       guint32 orig;
119       guint32 recv;
120       guint32 xmit;
121     } ts;
122     guint32 zero;  /* Unreachable */
123   } opt;
124 } e_icmp;
125
126 #define ICMP_ECHOREPLY     0
127 #define ICMP_UNREACH       3
128 #define ICMP_SOURCEQUENCH  4
129 #define ICMP_REDIRECT      5
130 #define ICMP_ECHO          8
131 #define ICMP_RTRADVERT     9
132 #define ICMP_RTRSOLICIT   10
133 #define ICMP_TIMXCEED     11
134 #define ICMP_PARAMPROB    12
135 #define ICMP_TSTAMP       13
136 #define ICMP_TSTAMPREPLY  14
137 #define ICMP_IREQ         15
138 #define ICMP_IREQREPLY    16
139 #define ICMP_MASKREQ      17
140 #define ICMP_MASKREPLY    18
141
142 /* ICMP UNREACHABLE */
143
144 #define ICMP_NET_UNREACH        0       /* Network Unreachable */
145 #define ICMP_HOST_UNREACH       1       /* Host Unreachable */
146 #define ICMP_PROT_UNREACH       2       /* Protocol Unreachable */
147 #define ICMP_PORT_UNREACH       3       /* Port Unreachable */
148 #define ICMP_FRAG_NEEDED        4       /* Fragmentation Needed/DF set */
149 #define ICMP_SR_FAILED          5       /* Source Route failed */
150 #define ICMP_NET_UNKNOWN        6
151 #define ICMP_HOST_UNKNOWN       7
152 #define ICMP_HOST_ISOLATED      8
153 #define ICMP_NET_ANO            9
154 #define ICMP_HOST_ANO           10
155 #define ICMP_NET_UNR_TOS        11
156 #define ICMP_HOST_UNR_TOS       12
157 #define ICMP_PKT_FILTERED       13      /* Packet filtered */
158 #define ICMP_PREC_VIOLATION     14      /* Precedence violation */
159 #define ICMP_PREC_CUTOFF        15      /* Precedence cut off */
160
161
162 /* IGMP structs and definitions */
163 typedef struct _e_igmp {
164   guint8  igmp_v_t; /* combines igmp_v and igmp_t */
165   guint8  igmp_unused;
166   guint16 igmp_cksum;
167   guint32 igmp_gaddr;
168 } e_igmp;
169
170 #define IGMP_M_QRY     0x01
171 #define IGMP_V1_M_RPT  0x02
172 #define IGMP_V2_LV_GRP 0x07
173 #define IGMP_DVMRP     0x03
174 #define IGMP_PIM       0x04
175 #define IGMP_V2_M_RPT  0x06
176 #define IGMP_MTRC_RESP 0x1e
177 #define IGMP_MTRC      0x1f
178
179 /* EIGRP Structs and Definitions. */    
180
181 /* EIGRP Opcodes */
182
183 #define EIGRP_UPDATE    0x01
184 #define EIGRP_REQUEST   0x02
185 #define EIGRP_QUERY     0x03
186 #define EIGRP_REPLY     0x04
187 #define EIGRP_HELLO     0x05
188
189 typedef struct _e_eigrp 
190    {
191    guint8 eigrp_version;
192    guint8 eigrp_opcode;
193    guint16 eigrp_checksum;
194    guint16 eigrp_subnets;
195    guint16 eigrp_networks;
196    guint32 eigrp_sequence;
197    guint32 eigrp_asnumber;
198    guint8 eigrp_type1;
199    guint8 eigrp_subtype1;
200    guint16 eigrp_length1;
201    guint16 eigrp_holdtime;
202    guint8 eigrp_type2;
203    guint8 eigrp_subtype2;
204    guint16 eigrp_length2;
205    guint8 eigrp_level;
206    guint16 eigrp_dummy;
207    } e_eigrp;
208
209 /* IP structs and definitions */
210
211 typedef struct _e_ip 
212    {
213    guint8  ip_v_hl; /* combines ip_v and ip_hl */
214    guint8  ip_tos;
215    guint16 ip_len;
216    guint16 ip_id;
217    guint16 ip_off;
218    guint8  ip_ttl;
219    guint8  ip_p;
220    guint16 ip_sum;
221    guint32 ip_src;
222    guint32 ip_dst;
223    } e_ip;
224
225 /* Offsets of fields within an IP header. */
226 #define IPH_V_HL        0
227 #define IPH_TOS         1
228 #define IPH_LEN         2
229 #define IPH_ID          4
230 #define IPH_TTL         6
231 #define IPH_OFF         8
232 #define IPH_P           9
233 #define IPH_SUM         10
234 #define IPH_SRC         12
235 #define IPH_DST         16
236
237 /* Minimum IP header length. */
238 #define IPH_MIN_LEN     20
239
240 /* IP flags. */
241 #define IP_CE           0x8000          /* Flag: "Congestion"           */
242 #define IP_DF           0x4000          /* Flag: "Don't Fragment"       */
243 #define IP_MF           0x2000          /* Flag: "More Fragments"       */
244 #define IP_OFFSET       0x1FFF          /* "Fragment Offset" part       */
245
246 #define IPTOS_TOS_MASK    0x1E
247 #define IPTOS_TOS(tos)    ((tos) & IPTOS_TOS_MASK)
248 #define IPTOS_NONE        0x00
249 #define IPTOS_LOWCOST     0x02
250 #define IPTOS_RELIABILITY 0x04
251 #define IPTOS_THROUGHPUT  0x08
252 #define IPTOS_LOWDELAY    0x10
253 #define IPTOS_SECURITY    0x1E
254
255 #define IPTOS_PREC_MASK         0xE0
256 #define IPTOS_PREC_SHIFT        5
257 #define IPTOS_PREC(tos)         (((tos)&IPTOS_PREC_MASK)>>IPTOS_PREC_SHIFT)
258 #define IPTOS_PREC_NETCONTROL           7
259 #define IPTOS_PREC_INTERNETCONTROL      6
260 #define IPTOS_PREC_CRITIC_ECP           5
261 #define IPTOS_PREC_FLASHOVERRIDE        4
262 #define IPTOS_PREC_FLASH                3
263 #define IPTOS_PREC_IMMEDIATE            2
264 #define IPTOS_PREC_PRIORITY             1
265 #define IPTOS_PREC_ROUTINE              0
266
267 /* IP options */
268 #define IPOPT_COPY              0x80
269
270 #define IPOPT_CONTROL           0x00
271 #define IPOPT_RESERVED1         0x20
272 #define IPOPT_MEASUREMENT       0x40
273 #define IPOPT_RESERVED2         0x60
274
275 #define IPOPT_END       (0 |IPOPT_CONTROL)
276 #define IPOPT_NOOP      (1 |IPOPT_CONTROL)
277 #define IPOPT_SEC       (2 |IPOPT_CONTROL|IPOPT_COPY)
278 #define IPOPT_LSRR      (3 |IPOPT_CONTROL|IPOPT_COPY)
279 #define IPOPT_TIMESTAMP (4 |IPOPT_MEASUREMENT)
280 #define IPOPT_RR        (7 |IPOPT_CONTROL)
281 #define IPOPT_SID       (8 |IPOPT_CONTROL|IPOPT_COPY)
282 #define IPOPT_SSRR      (9 |IPOPT_CONTROL|IPOPT_COPY)
283 #define IPOPT_RA        (20|IPOPT_CONTROL|IPOPT_COPY)
284
285 /* IP option lengths */
286 #define IPOLEN_SEC      11
287 #define IPOLEN_LSRR_MIN 3
288 #define IPOLEN_TIMESTAMP_MIN 5
289 #define IPOLEN_RR_MIN   3
290 #define IPOLEN_SID      4
291 #define IPOLEN_SSRR_MIN 3
292
293 #define IPSEC_UNCLASSIFIED      0x0000
294 #define IPSEC_CONFIDENTIAL      0xF135
295 #define IPSEC_EFTO              0x789A
296 #define IPSEC_MMMM              0xBC4D
297 #define IPSEC_RESTRICTED        0xAF13
298 #define IPSEC_SECRET            0xD788
299 #define IPSEC_TOPSECRET         0x6BC5
300 #define IPSEC_RESERVED1         0x35E2
301 #define IPSEC_RESERVED2         0x9AF1
302 #define IPSEC_RESERVED3         0x4D78
303 #define IPSEC_RESERVED4         0x24BD
304 #define IPSEC_RESERVED5         0x135E
305 #define IPSEC_RESERVED6         0x89AF
306 #define IPSEC_RESERVED7         0xC4D6
307 #define IPSEC_RESERVED8         0xE26B
308
309 #define IPOPT_TS_TSONLY         0               /* timestamps only */
310 #define IPOPT_TS_TSANDADDR      1               /* timestamps and addresses */
311 #define IPOPT_TS_PRESPEC        3               /* specified modules only */
312
313
314 void
315 capture_ip(const u_char *pd, int offset, guint32 cap_len, packet_counts *ld) {
316   switch (pd[offset + 9]) {
317     case IP_PROTO_TCP:
318       ld->tcp++;
319       break;
320     case IP_PROTO_UDP:
321       ld->udp++;
322       break;
323     case IP_PROTO_ICMP:
324       ld->icmp++;
325       break;
326     case IP_PROTO_OSPF:
327       ld->ospf++;
328       break;
329     case IP_PROTO_GRE:
330       ld->gre++;
331       break;
332     default:
333       ld->other++;
334   }
335 }
336
337 static void
338 dissect_ipopt_security(const ip_tcp_opt *optp, const u_char *opd, int offset,
339                         guint optlen, proto_tree *opt_tree)
340 {
341   proto_tree *field_tree = NULL;
342   proto_item *tf;
343   guint      val;
344   static const value_string secl_vals[] = {
345     {IPSEC_UNCLASSIFIED, "Unclassified"},
346     {IPSEC_CONFIDENTIAL, "Confidential"},
347     {IPSEC_EFTO,         "EFTO"        },
348     {IPSEC_MMMM,         "MMMM"        },
349     {IPSEC_RESTRICTED,   "Restricted"  },
350     {IPSEC_SECRET,       "Secret"      },
351     {IPSEC_TOPSECRET,    "Top secret"  },
352     {IPSEC_RESERVED1,    "Reserved"    },
353     {IPSEC_RESERVED2,    "Reserved"    },
354     {IPSEC_RESERVED3,    "Reserved"    },
355     {IPSEC_RESERVED4,    "Reserved"    },
356     {IPSEC_RESERVED5,    "Reserved"    },
357     {IPSEC_RESERVED6,    "Reserved"    },
358     {IPSEC_RESERVED7,    "Reserved"    },
359     {IPSEC_RESERVED8,    "Reserved"    },
360     {0,                  NULL          } };
361
362   tf = proto_tree_add_text(opt_tree, offset,      optlen, "%s:", optp->name);
363   field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
364   offset += 2;
365
366   val = pntohs(opd);
367   proto_tree_add_text(field_tree, offset,       2,
368               "Security: %s", val_to_str(val, secl_vals, "Unknown (0x%x)"));
369   offset += 2;
370   opd += 2;
371
372   val = pntohs(opd);
373   proto_tree_add_text(field_tree, offset,         2,
374               "Compartments: %d", val);
375   offset += 2;
376   opd += 2;
377
378   proto_tree_add_text(field_tree, offset,         2,
379               "Handling restrictions: %c%c", opd[0], opd[1]);
380   offset += 2;
381   opd += 2;
382
383   proto_tree_add_text(field_tree, offset,         3,
384               "Transmission control code: %c%c%c", opd[0], opd[1], opd[2]);
385 }
386
387 static void
388 dissect_ipopt_route(const ip_tcp_opt *optp, const u_char *opd, int offset,
389                         guint optlen, proto_tree *opt_tree)
390 {
391   proto_tree *field_tree = NULL;
392   proto_item *tf;
393   int ptr;
394   int optoffset = 0;
395   struct in_addr addr;
396
397   tf = proto_tree_add_text(opt_tree, offset,      optlen, "%s (%d bytes)",
398                                 optp->name, optlen);
399   field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
400
401   optoffset += 2;       /* skip past type and length */
402   optlen -= 2;          /* subtract size of type and length */
403
404   ptr = *opd;
405   proto_tree_add_text(field_tree, offset + optoffset, 1,
406               "Pointer: %d%s", ptr,
407               ((ptr < 4) ? " (points before first address)" :
408                ((ptr & 3) ? " (points to middle of address)" : "")));
409   optoffset++;
410   opd++;
411   optlen--;
412   ptr--;        /* ptr is 1-origin */
413
414   while (optlen > 0) {
415     if (optlen < 4) {
416       proto_tree_add_text(field_tree, offset,      optlen,
417         "(suboption would go past end of option)");
418       break;
419     }
420
421     /* Avoids alignment problems on many architectures. */
422     memcpy((char *)&addr, (char *)opd, sizeof(addr));
423
424     proto_tree_add_text(field_tree, offset + optoffset, 4,
425               "%s%s",
426               ((addr.s_addr == 0) ? "-" : (char *)get_hostname(addr.s_addr)),
427               ((optoffset == ptr) ? " <- (current)" : ""));
428     optoffset += 4;
429     opd += 4;
430     optlen -= 4;
431   }
432 }
433
434 static void
435 dissect_ipopt_sid(const ip_tcp_opt *optp, const u_char *opd, int offset,
436                         guint optlen, proto_tree *opt_tree)
437 {
438   proto_tree_add_text(opt_tree, offset,      optlen,
439     "%s: %d", optp->name, pntohs(opd));
440   return;
441 }
442
443 static void
444 dissect_ipopt_timestamp(const ip_tcp_opt *optp, const u_char *opd,
445     int offset, guint optlen, proto_tree *opt_tree)
446 {
447   proto_tree *field_tree = NULL;
448   proto_item *tf;
449   int        ptr;
450   int        optoffset = 0;
451   int        flg;
452   static const value_string flag_vals[] = {
453     {IPOPT_TS_TSONLY,    "Time stamps only"                      },
454     {IPOPT_TS_TSANDADDR, "Time stamp and address"                },
455     {IPOPT_TS_PRESPEC,   "Time stamps for prespecified addresses"},
456     {0,                  NULL                                    } };
457   struct in_addr addr;
458   guint ts;
459
460   tf = proto_tree_add_text(opt_tree, offset,      optlen, "%s:", optp->name);
461   field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
462
463   optoffset += 2;       /* skip past type and length */
464   optlen -= 2;          /* subtract size of type and length */
465
466   ptr = *opd;
467   proto_tree_add_text(field_tree, offset + optoffset, 1,
468               "Pointer: %d%s", ptr,
469               ((ptr < 5) ? " (points before first address)" :
470                (((ptr - 1) & 3) ? " (points to middle of address)" : "")));
471   optoffset++;
472   opd++;
473   optlen--;
474   ptr--;        /* ptr is 1-origin */
475
476   flg = *opd;
477   proto_tree_add_text(field_tree, offset + optoffset,   1,
478         "Overflow: %d", flg >> 4);
479   flg &= 0xF;
480   proto_tree_add_text(field_tree, offset + optoffset, 1,
481         "Flag: %s", val_to_str(flg, flag_vals, "Unknown (0x%x)"));
482   optoffset++;
483   opd++;
484   optlen--;
485
486   while (optlen > 0) {
487     if (flg == IPOPT_TS_TSANDADDR) {
488       if (optlen < 4) {
489         proto_tree_add_text(field_tree, offset + optoffset, optlen,
490           "(suboption would go past end of option)");
491         break;
492       }
493       /* XXX - check whether it goes past end of packet */
494       ts = pntohl(opd);
495       opd += 4;
496       optlen -= 4;
497       if (optlen < 4) {
498         proto_tree_add_text(field_tree, offset + optoffset, optlen,
499           "(suboption would go past end of option)");
500         break;
501       }
502       /* XXX - check whether it goes past end of packet */
503       memcpy((char *)&addr, (char *)opd, sizeof(addr));
504       opd += 4;
505       optlen -= 4;
506       proto_tree_add_text(field_tree, offset,      8,
507           "Address = %s, time stamp = %u",
508           ((addr.s_addr == 0) ? "-" :  (char *)get_hostname(addr.s_addr)),
509           ts);
510       optoffset += 8;
511     } else {
512       if (optlen < 4) {
513         proto_tree_add_text(field_tree, offset + optoffset, optlen,
514           "(suboption would go past end of option)");
515         break;
516       }
517       /* XXX - check whether it goes past end of packet */
518       ts = pntohl(opd);
519       opd += 4;
520       optlen -= 4;
521       proto_tree_add_text(field_tree, offset + optoffset, 4,
522           "Time stamp = %u", ts);
523       optoffset += 4;
524     }
525   }
526 }
527
528 static const ip_tcp_opt ipopts[] = {
529   {
530     IPOPT_END,
531     "EOL",
532     NULL,
533     NO_LENGTH,
534     0,
535     NULL,
536   },
537   {
538     IPOPT_NOOP,
539     "NOP",
540     NULL,
541     NO_LENGTH,
542     0,
543     NULL,
544   },
545   {
546     IPOPT_SEC,
547     "Security",
548     &ett_ip_option_sec,
549     FIXED_LENGTH,
550     IPOLEN_SEC,
551     dissect_ipopt_security
552   },
553   {
554     IPOPT_SSRR,
555     "Strict source route",
556     &ett_ip_option_route,
557     VARIABLE_LENGTH,
558     IPOLEN_SSRR_MIN,
559     dissect_ipopt_route
560   },
561   {
562     IPOPT_LSRR,
563     "Loose source route",
564     &ett_ip_option_route,
565     VARIABLE_LENGTH,
566     IPOLEN_LSRR_MIN,
567     dissect_ipopt_route
568   },
569   {
570     IPOPT_RR,
571     "Record route",
572     &ett_ip_option_route,
573     VARIABLE_LENGTH,
574     IPOLEN_RR_MIN,
575     dissect_ipopt_route
576   },
577   {
578     IPOPT_SID,
579     "Stream identifier",
580     NULL,
581     FIXED_LENGTH,
582     IPOLEN_SID,
583     dissect_ipopt_sid
584   },
585   {
586     IPOPT_TIMESTAMP,
587     "Time stamp",
588     &ett_ip_option_timestamp,
589     VARIABLE_LENGTH,
590     IPOLEN_TIMESTAMP_MIN,
591     dissect_ipopt_timestamp
592   }
593 };
594
595 #define N_IP_OPTS       (sizeof ipopts / sizeof ipopts[0])
596
597 /* Dissect the IP or TCP options in a packet. */
598 void
599 dissect_ip_tcp_options(const u_char *opd, int offset, guint length,
600                         const ip_tcp_opt *opttab, int nopts, int eol,
601                         proto_tree *opt_tree)
602 {
603   u_char            opt;
604   const ip_tcp_opt *optp;
605   opt_len_type      len_type;
606   int               optlen;
607   char             *name;
608   char              name_str[7+1+1+2+2+1+1];    /* "Unknown (0x%02x)" */
609   void            (*dissect)(const struct ip_tcp_opt *, const u_char *,
610                                 int, guint, proto_tree *);
611   guint             len;
612
613   while (length > 0) {
614     opt = *opd++;
615     for (optp = &opttab[0]; optp < &opttab[nopts]; optp++) {
616       if (optp->optcode == opt)
617         break;
618     }
619     if (optp == &opttab[nopts]) {
620       /* We assume that the only NO_LENGTH options are EOL and NOP options,
621          so that we can treat unknown options as VARIABLE_LENGTH with a
622          minimum of 2, and at least be able to move on to the next option
623          by using the length in the option. */
624       optp = NULL;      /* indicate that we don't know this option */
625       len_type = VARIABLE_LENGTH;
626       optlen = 2;
627       snprintf(name_str, sizeof name_str, "Unknown (0x%02x)", opt);
628       name = name_str;
629       dissect = NULL;
630     } else {
631       len_type = optp->len_type;
632       optlen = optp->optlen;
633       name = optp->name;
634       dissect = optp->dissect;
635     }
636     --length;      /* account for type byte */
637     if (len_type != NO_LENGTH) {
638       /* Option has a length. Is it in the packet? */
639       if (length == 0) {
640         /* Bogus - packet must at least include option code byte and
641            length byte! */
642         proto_tree_add_text(opt_tree, offset,      1,
643               "%s (length byte past end of options)", name);
644         return;
645       }
646       len = *opd++;  /* total including type, len */
647       --length;    /* account for length byte */
648       if (len < 2) {
649         /* Bogus - option length is too short to include option code and
650            option length. */
651         proto_tree_add_text(opt_tree, offset,      2,
652               "%s (with too-short option length = %u byte%s)", name,
653               len, plurality(len, "", "s"));
654         return;
655       } else if (len - 2 > length) {
656         /* Bogus - option goes past the end of the header. */
657         proto_tree_add_text(opt_tree, offset,      length,
658               "%s (option length = %u byte%s says option goes past end of options)",
659               name, len, plurality(len, "", "s"));
660         return;
661       } else if (len_type == FIXED_LENGTH && len != optlen) {
662         /* Bogus - option length isn't what it's supposed to be for this
663            option. */
664         proto_tree_add_text(opt_tree, offset,      len,
665               "%s (with option length = %u byte%s; should be %u)", name,
666               len, plurality(len, "", "s"), optlen);
667         return;
668       } else if (len_type == VARIABLE_LENGTH && len < optlen) {
669         /* Bogus - option length is less than what it's supposed to be for
670            this option. */
671         proto_tree_add_text(opt_tree, offset,      len,
672               "%s (with option length = %u byte%s; should be >= %u)", name,
673               len, plurality(len, "", "s"), optlen);
674         return;
675       } else {
676         if (optp == NULL) {
677           proto_tree_add_text(opt_tree, offset,    len, "%s (%d byte%s)",
678                                 name, len, plurality(len, "", "s"));
679         } else {
680           if (dissect != NULL) {
681             /* Option has a dissector. */
682             (*dissect)(optp, opd, offset,          len, opt_tree);
683           } else {
684             /* Option has no data, hence no dissector. */
685             proto_tree_add_text(opt_tree, offset,  len, "%s", name);
686           }
687         }
688         len -= 2;       /* subtract size of type and length */
689         offset += 2 + len;
690       }
691       opd += len;
692       length -= len;
693     } else {
694       proto_tree_add_text(opt_tree, offset,      1, "%s", name);
695       offset += 1;
696     }
697     if (opt == eol)
698       break;
699   }
700 }
701
702 static const value_string proto_vals[] = { {IP_PROTO_ICMP, "ICMP"},
703                                            {IP_PROTO_IGMP, "IGMP"},
704                                            {IP_PROTO_EIGRP, "IGRP/EIGRP"},
705                                            {IP_PROTO_TCP,  "TCP" },
706                                            {IP_PROTO_UDP,  "UDP" },
707                                            {IP_PROTO_OSPF, "OSPF"},
708                                            {IP_PROTO_RSVP, "RSVP"},
709                                            {IP_PROTO_AH,   "AH"  },
710                                            {IP_PROTO_GRE,  "GRE" },
711                                            {IP_PROTO_ESP,  "ESP" },
712                                            {IP_PROTO_IPV6, "IPv6"},
713                                            {IP_PROTO_PIM,  "PIM" },
714                                            {0,             NULL  } };
715
716 static const value_string precedence_vals[] = {
717                   { IPTOS_PREC_ROUTINE,         "routine"              },
718                   { IPTOS_PREC_PRIORITY,        "priority"             },
719                   { IPTOS_PREC_IMMEDIATE,       "immediate"            },
720                   { IPTOS_PREC_FLASH,           "flash"                },
721                   { IPTOS_PREC_FLASHOVERRIDE,   "flash override"       },
722                   { IPTOS_PREC_CRITIC_ECP,      "CRITIC/ECP"           },
723                   { IPTOS_PREC_INTERNETCONTROL, "internetwork control" },
724                   { IPTOS_PREC_NETCONTROL,      "network control"      },
725                   { 0,                          NULL                   } };
726
727 static const value_string iptos_vals[] = {
728         { IPTOS_NONE,           "None" },
729         { IPTOS_LOWCOST,        "Minimize cost" },
730         { IPTOS_RELIABILITY,    "Maximize reliability" },
731         { IPTOS_THROUGHPUT,     "Maximize throughput" },
732         { IPTOS_LOWDELAY,       "Minimize delay" },
733         { IPTOS_SECURITY,       "Maximize security" },
734         { 0,                    NULL }
735 };
736
737 static const true_false_string tos_set_low = {
738   "Low",
739   "Normal"
740 };
741
742 static const true_false_string tos_set_high = {
743   "High",
744   "Normal"
745 };
746
747 static const true_false_string flags_set_truth = {
748   "Set",
749   "Not set"
750 };
751
752 static char *ip_checksum_state(e_ip *iph)
753 {
754     unsigned long Sum;
755     unsigned char *Ptr, *PtrEnd;
756     unsigned short word;
757
758     Sum    = 0;
759     PtrEnd = (lo_nibble(iph->ip_v_hl) * 4 + (char *)iph);
760     for (Ptr = (unsigned char *) iph; Ptr < PtrEnd; Ptr += 2) {
761         memcpy(&word, Ptr, sizeof word);
762         Sum += word;
763     }
764
765     Sum = (Sum & 0xFFFF) + (Sum >> 16);
766     Sum = (Sum & 0xFFFF) + (Sum >> 16);
767
768     if (Sum != 0xffff)
769         return "incorrect";
770
771     return "correct";
772 }
773
774 void
775 dissect_ip(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
776   e_ip       iph;
777   proto_tree *ip_tree, *field_tree;
778   proto_item *ti, *tf;
779   gchar      tos_str[32];
780   guint      hlen, optlen, len;
781   guint16    flags;
782   int        advance;
783   guint8     nxt;
784
785   /* To do: check for errs, etc. */
786   if (!BYTES_ARE_IN_FRAME(offset, IPH_MIN_LEN)) {
787     dissect_data(pd, offset, fd, tree);
788     return;
789   }
790
791   /* Avoids alignment problems on many architectures. */
792   memcpy(&iph, &pd[offset], sizeof(e_ip));
793   iph.ip_len = ntohs(iph.ip_len);
794   iph.ip_id  = ntohs(iph.ip_id);
795   iph.ip_off = ntohs(iph.ip_off);
796   iph.ip_sum = ntohs(iph.ip_sum);
797
798   /* Length of IP datagram plus headers above it. */
799   len = iph.ip_len + offset;
800
801   /* Set the payload and captured-payload lengths to the minima of (the
802      IP length plus the length of the headers above it) and the frame
803      lengths. */
804   if (pi.len > len)
805     pi.len = len;
806   if (pi.captured_len > len)
807     pi.captured_len = len;
808
809   /* XXX - check to make sure this is at least IPH_MIN_LEN. */
810   hlen = lo_nibble(iph.ip_v_hl) * 4;    /* IP header length, in bytes */
811   
812   switch (iph.ip_p) {
813     case IP_PROTO_ICMP:
814     case IP_PROTO_IGMP:
815     case IP_PROTO_TCP:
816     case IP_PROTO_UDP:
817     case IP_PROTO_OSPF:
818     case IP_PROTO_GRE:
819     case IP_PROTO_ESP:
820     case IP_PROTO_AH:
821     case IP_PROTO_IPV6:
822     case IP_PROTO_PIM:
823       /* Names are set in the associated dissect_* routines */
824       break;
825     default:
826       if (check_col(fd, COL_PROTOCOL))
827         col_add_str(fd, COL_PROTOCOL, "IP");
828       if (check_col(fd, COL_INFO))
829         col_add_fstr(fd, COL_INFO, "%s (0x%02x)",
830             ipprotostr(iph.ip_p), iph.ip_p);
831   }
832
833   if (tree) {
834
835     switch (IPTOS_TOS(iph.ip_tos)) {
836       case IPTOS_NONE:
837         strcpy(tos_str, "None");
838         break;
839       case IPTOS_LOWCOST:
840         strcpy(tos_str, "Minimize cost");
841         break;
842       case IPTOS_RELIABILITY:
843         strcpy(tos_str, "Maximize reliability");
844         break;
845       case IPTOS_THROUGHPUT:
846         strcpy(tos_str, "Maximize throughput");
847         break;
848       case IPTOS_LOWDELAY:
849         strcpy(tos_str, "Minimize delay");
850         break;
851       case IPTOS_SECURITY:
852         strcpy(tos_str, "Maximize security");
853         break;
854       default:
855         strcpy(tos_str, "Unknown.  Malformed?");
856         break;
857     }
858
859     ti = proto_tree_add_item(tree, proto_ip, offset, hlen, NULL);
860     ip_tree = proto_item_add_subtree(ti, ett_ip);
861
862     proto_tree_add_item(ip_tree, hf_ip_version, offset, 1, hi_nibble(iph.ip_v_hl));
863     proto_tree_add_item_format(ip_tree, hf_ip_hdr_len, offset, 1, hlen,
864         "Header length: %u bytes", hlen);
865     tf = proto_tree_add_item_format(ip_tree, hf_ip_tos, offset + 1, 1, iph.ip_tos,
866         "Type of service: 0x%02x (%s)", iph.ip_tos,
867         val_to_str( IPTOS_TOS(iph.ip_tos), iptos_vals, "Unknown") );
868
869     field_tree = proto_item_add_subtree(tf, ett_ip_tos);
870     proto_tree_add_item(field_tree, hf_ip_tos_precedence, offset + 1, 1, iph.ip_tos);
871     proto_tree_add_item(field_tree, hf_ip_tos_delay, offset + 1, 1, iph.ip_tos);
872     proto_tree_add_item(field_tree, hf_ip_tos_throughput, offset + 1, 1, iph.ip_tos);
873     proto_tree_add_item(field_tree, hf_ip_tos_reliability, offset + 1, 1, iph.ip_tos);
874     proto_tree_add_item(field_tree, hf_ip_tos_cost, offset + 1, 1, iph.ip_tos);
875     proto_tree_add_item(ip_tree, hf_ip_len, offset +  2, 2, iph.ip_len);
876     proto_tree_add_item(ip_tree, hf_ip_id, offset +  4, 2, iph.ip_id);
877
878     flags = (iph.ip_off & (IP_DF|IP_MF)) >> 12;
879     tf = proto_tree_add_item(ip_tree, hf_ip_flags, offset +  6, 1, flags);
880     field_tree = proto_item_add_subtree(tf, ett_ip_off);
881     proto_tree_add_item(field_tree, hf_ip_flags_df, offset + 6, 1, flags),
882     proto_tree_add_item(field_tree, hf_ip_flags_mf, offset + 6, 1, flags),
883
884     proto_tree_add_item(ip_tree, hf_ip_frag_offset, offset +  6, 2,
885       iph.ip_off & IP_OFFSET);
886     proto_tree_add_item(ip_tree, hf_ip_ttl, offset +  8, 1, iph.ip_ttl);
887     proto_tree_add_item_format(ip_tree, hf_ip_proto, offset +  9, 1, iph.ip_p,
888         "Protocol: %s (0x%02x)", ipprotostr(iph.ip_p), iph.ip_p);
889     proto_tree_add_item_format(ip_tree, hf_ip_checksum, offset + 10, 2, iph.ip_sum,
890         "Header checksum: 0x%04x (%s)", iph.ip_sum, ip_checksum_state((e_ip*) &pd[offset]));
891     proto_tree_add_item(ip_tree, hf_ip_src, offset + 12, 4, iph.ip_src);
892     proto_tree_add_item(ip_tree, hf_ip_dst, offset + 16, 4, iph.ip_dst);
893     proto_tree_add_item_hidden(ip_tree, hf_ip_addr, offset + 12, 4, iph.ip_src);
894     proto_tree_add_item_hidden(ip_tree, hf_ip_addr, offset + 16, 4, iph.ip_dst);
895
896     /* Decode IP options, if any. */
897     if (hlen > sizeof (e_ip)) {
898       /* There's more than just the fixed-length header.  Decode the
899          options. */
900       optlen = hlen - sizeof (e_ip);    /* length of options, in bytes */
901       tf = proto_tree_add_text(ip_tree, offset +  20, optlen,
902         "Options: (%d bytes)", optlen);
903       field_tree = proto_item_add_subtree(tf, ett_ip_options);
904       dissect_ip_tcp_options(&pd[offset + 20], offset + 20, optlen,
905          ipopts, N_IP_OPTS, IPOPT_END, field_tree);
906     }
907   }
908
909   pi.ipproto = iph.ip_p;
910   pi.iplen = iph.ip_len;
911   pi.iphdrlen = lo_nibble(iph.ip_v_hl);
912   SET_ADDRESS(&pi.net_src, AT_IPv4, 4, &pd[offset + IPH_SRC]);
913   SET_ADDRESS(&pi.src, AT_IPv4, 4, &pd[offset + IPH_SRC]);
914   SET_ADDRESS(&pi.net_dst, AT_IPv4, 4, &pd[offset + IPH_DST]);
915   SET_ADDRESS(&pi.dst, AT_IPv4, 4, &pd[offset + IPH_DST]);
916
917   /* Skip over header + options */
918   offset += hlen;
919   nxt = iph.ip_p;
920   if (iph.ip_off & IP_OFFSET) {
921     /* fragmented */
922     if (check_col(fd, COL_PROTOCOL))
923       col_add_str(fd, COL_PROTOCOL, "IP");
924     if (check_col(fd, COL_INFO))
925       col_add_fstr(fd, COL_INFO, "Fragmented IP protocol (proto=%s 0x%02x, off=%d)",
926         ipprotostr(iph.ip_p), iph.ip_p, iph.ip_off & IP_OFFSET);
927     dissect_data(pd, offset, fd, tree);
928     return;
929   }
930
931 again:
932   switch (nxt) {
933     case IP_PROTO_ICMP:
934       dissect_icmp(pd, offset, fd, tree);
935      break;
936     case IP_PROTO_IGMP:
937       dissect_igmp(pd, offset, fd, tree);
938      break;
939     case IP_PROTO_EIGRP:
940       dissect_eigrp(pd, offset, fd, tree);
941       break;  
942     case IP_PROTO_TCP:
943       dissect_tcp(pd, offset, fd, tree);
944       break;
945     case IP_PROTO_UDP:
946       dissect_udp(pd, offset, fd, tree);
947       break;
948     case IP_PROTO_OSPF:
949       dissect_ospf(pd, offset, fd, tree);
950       break;
951     case IP_PROTO_RSVP:
952       dissect_rsvp(pd, offset, fd, tree);
953       break;
954     case IP_PROTO_AH:
955       advance = dissect_ah(pd, offset, fd, tree);
956       nxt = pd[offset];
957       offset += advance;
958       goto again;
959     case IP_PROTO_GRE:
960       dissect_gre(pd, offset, fd, tree);
961       break;
962     case IP_PROTO_ESP:
963       dissect_esp(pd, offset, fd, tree);
964       break;
965     case IP_PROTO_IPV6:
966       dissect_ipv6(pd, offset, fd, tree);
967       break;
968     case IP_PROTO_PIM:
969       dissect_pim(pd, offset, fd, tree);
970       break;
971     case IP_PROTO_IPCOMP:
972       dissect_ipcomp(pd, offset, fd, tree);
973       break;
974     case IP_PROTO_VRRP:
975       dissect_vrrp(pd, offset, fd, tree);
976       break;
977     default:
978       dissect_data(pd, offset, fd, tree);
979       break;
980   }
981 }
982
983
984 static const gchar *unreach_str[] = {"Network unreachable",
985                                      "Host unreachable",
986                                      "Protocol unreachable",
987                                      "Port unreachable",
988                                      "Fragmentation needed",
989                                      "Source route failed",
990                                      "Destination network unknown",
991                                      "Destination host unknown",
992                                      "Source host isolated",
993                                      "Network administratively prohibited",
994                                      "Host administratively prohibited",
995                                      "Network unreachable for TOS",
996                                      "Host unreachable for TOS",
997                                      "Communication administratively filtered",
998                                      "Host precedence violation",
999                                      "Precedence cutoff in effect"};
1000                                      
1001 #define N_UNREACH       (sizeof unreach_str / sizeof unreach_str[0])
1002
1003 static const gchar *redir_str[] = {"Redirect for network",
1004                                    "Redirect for host",
1005                                    "Redirect for TOS and network",
1006                                    "Redirect for TOS and host"};
1007
1008 #define N_REDIRECT      (sizeof redir_str / sizeof redir_str[0])
1009
1010 static const gchar *ttl_str[] = {"TTL equals 0 during transit",
1011                                  "TTL equals 0 during reassembly"};
1012                                  
1013 #define N_TIMXCEED      (sizeof ttl_str / sizeof ttl_str[0])
1014
1015 static const gchar *par_str[] = {"IP header bad", "Required option missing"};
1016
1017 #define N_PARAMPROB     (sizeof par_str / sizeof par_str[0])
1018
1019 void
1020 dissect_icmp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
1021   e_icmp     ih;
1022   proto_tree *icmp_tree;
1023   proto_item *ti;
1024   guint16    cksum;
1025   gchar      type_str[64], code_str[64] = "";
1026   guint8     num_addrs = 0;
1027   guint8     addr_entry_size = 0;
1028   int        i;
1029
1030   /* Avoids alignment problems on many architectures. */
1031   memcpy(&ih, &pd[offset], sizeof(e_icmp));
1032   /* To do: check for runts, errs, etc. */
1033   cksum = ntohs(ih.icmp_cksum);
1034   
1035   switch (ih.icmp_type) {
1036     case ICMP_ECHOREPLY:
1037       strcpy(type_str, "Echo (ping) reply");
1038       break;
1039     case ICMP_UNREACH:
1040       strcpy(type_str, "Destination unreachable");
1041       if (ih.icmp_code < N_UNREACH) {
1042         sprintf(code_str, "(%s)", unreach_str[ih.icmp_code]);
1043       } else {
1044         strcpy(code_str, "(Unknown - error?)");
1045       }
1046       break;
1047     case ICMP_SOURCEQUENCH:
1048       strcpy(type_str, "Source quench (flow control)");
1049       break;
1050     case ICMP_REDIRECT:
1051       strcpy(type_str, "Redirect");
1052       if (ih.icmp_code < N_REDIRECT) {
1053         sprintf(code_str, "(%s)", redir_str[ih.icmp_code]);
1054       } else {
1055         strcpy(code_str, "(Unknown - error?)");
1056       }
1057       break;
1058     case ICMP_ECHO:
1059       strcpy(type_str, "Echo (ping) request");
1060       break;
1061     case ICMP_RTRADVERT:
1062       strcpy(type_str, "Router advertisement");
1063       break;
1064     case ICMP_RTRSOLICIT:
1065       strcpy(type_str, "Router solicitation");
1066       break;
1067     case ICMP_TIMXCEED:
1068       strcpy(type_str, "Time-to-live exceeded");
1069       if (ih.icmp_code < N_TIMXCEED) {
1070         sprintf(code_str, "(%s)", ttl_str[ih.icmp_code]);
1071       } else {
1072         strcpy(code_str, "(Unknown - error?)");
1073       }
1074       break;
1075     case ICMP_PARAMPROB:
1076       strcpy(type_str, "Parameter problem");
1077       if (ih.icmp_code < N_PARAMPROB) {
1078         sprintf(code_str, "(%s)", par_str[ih.icmp_code]);
1079       } else {
1080         strcpy(code_str, "(Unknown - error?)");
1081       }
1082       break;
1083     case ICMP_TSTAMP:
1084       strcpy(type_str, "Timestamp request");
1085       break;
1086     case ICMP_TSTAMPREPLY:
1087       strcpy(type_str, "Timestamp reply");
1088       break;
1089     case ICMP_IREQ:
1090       strcpy(type_str, "Information request");
1091       break;
1092     case ICMP_IREQREPLY:
1093       strcpy(type_str, "Information reply");
1094       break;
1095     case ICMP_MASKREQ:
1096       strcpy(type_str, "Address mask request");
1097       break;
1098     case ICMP_MASKREPLY:
1099       strcpy(type_str, "Address mask reply");
1100       break;
1101     default:
1102       strcpy(type_str, "Unknown ICMP (obsolete or malformed?)");
1103   }
1104
1105   if (check_col(fd, COL_PROTOCOL))
1106     col_add_str(fd, COL_PROTOCOL, "ICMP");
1107   if (check_col(fd, COL_INFO))
1108     col_add_str(fd, COL_INFO, type_str);
1109
1110   if (tree) {
1111     ti = proto_tree_add_item(tree, proto_icmp, offset, 4, NULL);
1112     icmp_tree = proto_item_add_subtree(ti, ett_icmp);
1113     proto_tree_add_item_format(icmp_tree, hf_icmp_type, offset,      1, 
1114                                ih.icmp_type,
1115                                "Type: %d (%s)",
1116                                ih.icmp_type, type_str);
1117     proto_tree_add_item_format(icmp_tree, hf_icmp_code, offset +  1, 1, 
1118                                ih.icmp_code,
1119                                "Code: %d %s",
1120                                ih.icmp_code, code_str);
1121     proto_tree_add_item(icmp_tree, hf_icmp_checksum, offset +  2, 2, 
1122                         cksum);
1123
1124     /* Decode the second 4 bytes of the packet. */
1125     switch (ih.icmp_type) {
1126       case ICMP_ECHOREPLY:
1127       case ICMP_ECHO:
1128       case ICMP_TSTAMP:
1129       case ICMP_TSTAMPREPLY:
1130       case ICMP_IREQ:
1131       case ICMP_IREQREPLY:
1132       case ICMP_MASKREQ:
1133       case ICMP_MASKREPLY:
1134         proto_tree_add_text(icmp_tree, offset +  4, 2, "Identifier: 0x%04x",
1135           pntohs(&pd[offset +  4]));
1136         proto_tree_add_text(icmp_tree, offset +  6, 2, "Sequence number: %u",
1137           pntohs(&pd[offset +  6]));
1138         break;
1139
1140        case ICMP_UNREACH:
1141          switch (ih.icmp_code) {
1142            case ICMP_FRAG_NEEDED:
1143                  proto_tree_add_text(icmp_tree, offset +  6, 2, "MTU of next hop: %u",
1144                    pntohs(&pd[offset + 6]));
1145                  break;
1146            }
1147          break;
1148
1149       case ICMP_RTRADVERT:
1150         num_addrs = pd[offset + 4];
1151         proto_tree_add_text(icmp_tree, offset +  4, 1, "Number of addresses: %u",
1152           num_addrs);
1153         addr_entry_size = pd[offset + 5];
1154         proto_tree_add_text(icmp_tree, offset +  5, 1, "Address entry size: %u",
1155           addr_entry_size);
1156         proto_tree_add_text(icmp_tree, offset +  6, 2, "Lifetime: %s",
1157           time_secs_to_str(pntohs(&pd[offset +  6])));
1158         break;
1159
1160       case ICMP_PARAMPROB:
1161         proto_tree_add_text(icmp_tree, offset +  4, 1, "Pointer: %u",
1162           pd[offset +  4]);
1163         break;
1164
1165       case ICMP_REDIRECT:
1166         proto_tree_add_text(icmp_tree, offset +  4, 4, "Gateway address: %s",
1167           ip_to_str((guint8 *)&pd[offset +  4]));
1168         break;
1169     }
1170
1171     /* Decode the additional information in the packet.  */
1172     switch (ih.icmp_type) {
1173       case ICMP_UNREACH:
1174       case ICMP_TIMXCEED:
1175       case ICMP_PARAMPROB:
1176       case ICMP_SOURCEQUENCH:
1177       case ICMP_REDIRECT:
1178         /* Decode the IP header and first 64 bits of data from the
1179            original datagram.
1180
1181            XXX - for now, just display it as data; not all dissection
1182            routines can handle a short packet without exploding. */
1183         dissect_data(pd, offset + 8, fd, icmp_tree);
1184         break;
1185
1186       case ICMP_ECHOREPLY:
1187       case ICMP_ECHO:
1188         dissect_data(pd, offset + 8, fd, icmp_tree);
1189         break;
1190
1191       case ICMP_RTRADVERT:
1192         if (addr_entry_size == 2) {
1193           for (i = 0; i < num_addrs; i++) {
1194             proto_tree_add_text(icmp_tree, offset + 8 + (i*8), 4,
1195               "Router address: %s",
1196               ip_to_str((guint8 *)&pd[offset +  8 + (i*8)]));
1197             proto_tree_add_text(icmp_tree, offset + 12 + (i*8), 4,
1198               "Preference level: %d", pntohl(&pd[offset + 12 + (i*8)]));
1199           }
1200         } else
1201           dissect_data(pd, offset + 8, fd, icmp_tree);
1202         break;
1203
1204       case ICMP_TSTAMP:
1205       case ICMP_TSTAMPREPLY:
1206         proto_tree_add_text(icmp_tree, offset +  8, 4, "Originate timestamp: %u",
1207           pntohl(&pd[offset +  8]));
1208         proto_tree_add_text(icmp_tree, offset + 12, 4, "Receive timestamp: %u",
1209           pntohl(&pd[offset + 12]));
1210         proto_tree_add_text(icmp_tree, offset + 16, 4, "Transmit timestamp: %u",
1211           pntohl(&pd[offset + 16]));
1212         break;
1213
1214     case ICMP_MASKREQ:
1215     case ICMP_MASKREPLY:
1216         proto_tree_add_text(icmp_tree, offset +  8, 4, "Address mask: %s (0x%8x)",
1217           ip_to_str((guint8 *)&pd[offset +  8]), pntohl(&pd[offset +  8]));
1218         break;
1219     }
1220   }
1221 }
1222
1223 void
1224 dissect_igmp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
1225   e_igmp     ih;
1226   proto_tree *igmp_tree;
1227   proto_item *ti;
1228   guint16    cksum;
1229   gchar      type_str[64] = "";
1230
1231   /* Avoids alignment problems on many architectures. */
1232   memcpy(&ih, &pd[offset], sizeof(e_igmp));
1233   /* To do: check for runts, errs, etc. */
1234   cksum = ntohs(ih.igmp_cksum);
1235   
1236   switch (lo_nibble(ih.igmp_v_t)) {
1237     case IGMP_M_QRY:
1238       strcpy(type_str, "Router query");
1239       break;
1240     case IGMP_V1_M_RPT:
1241       strcpy(type_str, "Host response (v1)");
1242       break;
1243     case IGMP_V2_LV_GRP:
1244       strcpy(type_str, "Leave group (v2)");
1245       break;
1246     case IGMP_DVMRP:
1247       strcpy(type_str, "DVMRP");
1248       break;
1249     case IGMP_PIM:
1250       strcpy(type_str, "PIM");
1251       break;
1252     case IGMP_V2_M_RPT:
1253       strcpy(type_str, "Host response (v2)");
1254       break;
1255     case IGMP_MTRC_RESP:
1256       strcpy(type_str, "Traceroute response");
1257       break;
1258     case IGMP_MTRC:
1259       strcpy(type_str, "Traceroute message");
1260       break;
1261     default:
1262       strcpy(type_str, "Unknown IGMP");
1263   }
1264
1265   if (check_col(fd, COL_PROTOCOL))
1266     col_add_str(fd, COL_PROTOCOL, "IGMP");
1267   if (check_col(fd, COL_INFO))
1268     col_add_str(fd, COL_INFO, type_str);
1269   if (tree) {
1270     ti = proto_tree_add_item(tree, proto_igmp, offset, 8, NULL);
1271     igmp_tree = proto_item_add_subtree(ti, ett_igmp);
1272     proto_tree_add_item(igmp_tree, hf_igmp_version, offset,     1, 
1273                         hi_nibble(ih.igmp_v_t));
1274     proto_tree_add_item_format(igmp_tree, hf_igmp_type,  offset    , 1, 
1275                                lo_nibble(ih.igmp_v_t),
1276                                "Type: %d (%s)",
1277                                lo_nibble(ih.igmp_v_t), type_str);
1278     proto_tree_add_item_format(igmp_tree, hf_igmp_unused, offset + 1, 1,
1279                                ih.igmp_unused,
1280                                "Unused: 0x%02x",
1281                                ih.igmp_unused);
1282     proto_tree_add_item(igmp_tree, hf_igmp_checksum, offset + 2, 2, 
1283                         cksum);
1284     proto_tree_add_item(igmp_tree, hf_igmp_group, offset + 4, 4, 
1285                         ih.igmp_gaddr);
1286   }
1287 }
1288
1289 void
1290 proto_register_igmp(void)
1291 {
1292         static hf_register_info hf[] = {
1293
1294                 { &hf_igmp_version,
1295                 { "Version",            "igmp.version", FT_UINT8, BASE_DEC, NULL, 0x0,
1296                         "" }},
1297
1298                 { &hf_igmp_type,
1299                 { "Type",               "igmp.type", FT_UINT8, BASE_DEC, NULL, 0x0,
1300                         "" }},
1301
1302                 { &hf_igmp_unused,
1303                 { "Unused",             "igmp.unused", FT_UINT8, BASE_DEC, NULL, 0x0,
1304                         "" }},
1305
1306                 { &hf_igmp_checksum,
1307                 { "Checksum",           "igmp.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
1308                         "" }},
1309
1310                 { &hf_igmp_group,
1311                 { "Group address",      "igmp.group", FT_IPv4, BASE_NONE, NULL, 0x0,
1312                         "" }},
1313         };
1314         static gint *ett[] = {
1315                 &ett_igmp,
1316         };
1317
1318         proto_igmp = proto_register_protocol ("Internet Group Management Protocol", "igmp");
1319         proto_register_field_array(proto_igmp, hf, array_length(hf));
1320         proto_register_subtree_array(ett, array_length(ett));
1321 }
1322
1323 void
1324 proto_register_ip(void)
1325 {
1326         static hf_register_info hf[] = {
1327
1328                 { &hf_ip_version,
1329                 { "Version",            "ip.version", FT_UINT8, BASE_DEC, NULL, 0x0,
1330                         "" }},
1331
1332                 { &hf_ip_hdr_len,
1333                 { "Header Length",      "ip.hdr_len", FT_UINT8, BASE_DEC, NULL, 0x0,
1334                         "" }},
1335
1336                 { &hf_ip_tos,
1337                 { "Type of Service",    "ip.tos", FT_UINT8, BASE_DEC, NULL, 0x0,
1338                         "" }},
1339
1340                 { &hf_ip_tos_precedence,
1341                 { "Precedence",         "ip.tos.precedence", FT_UINT8, BASE_DEC, VALS(precedence_vals),
1342                         IPTOS_PREC_MASK,
1343                         "" }},
1344
1345                 { &hf_ip_tos_delay,
1346                 { "Delay",              "ip.tos.delay", FT_BOOLEAN, 8, TFS(&tos_set_low),
1347                         IPTOS_LOWDELAY,
1348                         "" }},
1349
1350                 { &hf_ip_tos_throughput,
1351                 { "Throughput",         "ip.tos.throughput", FT_BOOLEAN, 8, TFS(&tos_set_high),
1352                         IPTOS_THROUGHPUT,
1353                         "" }},
1354
1355                 { &hf_ip_tos_reliability,
1356                 { "Reliability",        "ip.tos.reliability", FT_BOOLEAN, 8, TFS(&tos_set_high),
1357                         IPTOS_RELIABILITY,
1358                         "" }},
1359
1360                 { &hf_ip_tos_cost,
1361                 { "Cost",               "ip.tos.cost", FT_BOOLEAN, 8, TFS(&tos_set_low),
1362                         IPTOS_LOWCOST,
1363                         "" }},
1364
1365                 { &hf_ip_len,
1366                 { "Total Length",       "ip.len", FT_UINT16, BASE_DEC, NULL, 0x0,
1367                         "" }},
1368
1369                 { &hf_ip_id,
1370                 { "Identification",     "ip.id", FT_UINT16, BASE_HEX, NULL, 0x0,
1371                         "" }},
1372
1373                 { &hf_ip_dst,
1374                 { "Destination",        "ip.dst", FT_IPv4, BASE_NONE, NULL, 0x0,
1375                         "" }},
1376
1377                 { &hf_ip_src,
1378                 { "Source",             "ip.src", FT_IPv4, BASE_NONE, NULL, 0x0,
1379                         "" }},
1380
1381                 { &hf_ip_addr,
1382                 { "Source or Destination Address", "ip.addr", FT_IPv4, BASE_NONE, NULL, 0x0,
1383                         "" }},
1384
1385                 { &hf_ip_flags,
1386                 { "Flags",              "ip.flags", FT_UINT8, BASE_HEX, NULL, 0x0,
1387                         "" }},
1388
1389                 { &hf_ip_flags_df,
1390                 { "Don't fragment",     "ip.flags.df", FT_BOOLEAN, 4, TFS(&flags_set_truth), IP_DF>>12,
1391                         "" }},
1392
1393                 { &hf_ip_flags_mf,
1394                 { "More fragments",     "ip.flags.mf", FT_BOOLEAN, 4, TFS(&flags_set_truth), IP_MF>>12,
1395                         "" }},
1396
1397                 { &hf_ip_frag_offset,
1398                 { "Fragment offset",    "ip.frag_offset", FT_UINT16, BASE_DEC, NULL, 0x0,
1399                         "" }},
1400
1401                 { &hf_ip_ttl,
1402                 { "Time to live",       "ip.ttl", FT_UINT8, BASE_DEC, NULL, 0x0,
1403                         "" }},
1404
1405                 { &hf_ip_proto,
1406                 { "Protocol",           "ip.proto", FT_UINT8, BASE_HEX, NULL, 0x0,
1407                         "" }},
1408
1409                 { &hf_ip_checksum,
1410                 { "Header checksum",    "ip.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
1411                         "" }},
1412         };
1413         static gint *ett[] = {
1414                 &ett_ip,
1415                 &ett_ip_tos,
1416                 &ett_ip_off,
1417                 &ett_ip_options,
1418                 &ett_ip_option_sec,
1419                 &ett_ip_option_route,
1420                 &ett_ip_option_timestamp,
1421         };
1422
1423         proto_ip = proto_register_protocol ("Internet Protocol", "ip");
1424         proto_register_field_array(proto_ip, hf, array_length(hf));
1425         proto_register_subtree_array(ett, array_length(ett));
1426 }
1427
1428 void
1429 proto_register_icmp(void)
1430 {
1431   static hf_register_info hf[] = {
1432     
1433     { &hf_icmp_type,
1434       { "Type",         "icmp.type",            FT_UINT8, BASE_DEC,     NULL, 0x0,
1435         "" }},
1436
1437     { &hf_icmp_code,
1438       { "Code",         "icmp.code",            FT_UINT8, BASE_HEX,     NULL, 0x0,
1439         "" }},    
1440
1441     { &hf_icmp_checksum,
1442       { "Checksum",     "icmp.checksum",        FT_UINT16, BASE_HEX,    NULL, 0x0,
1443         "" }},
1444   };
1445   static gint *ett[] = {
1446     &ett_icmp,
1447   };
1448   
1449   proto_icmp = proto_register_protocol ("Internet Control Message Protocol", 
1450                                         "icmp");
1451   proto_register_field_array(proto_icmp, hf, array_length(hf));
1452   proto_register_subtree_array(ett, array_length(ett));
1453 }
1454
1455 static int proto_eigrp = -1;
1456
1457 static gint ett_eigrp = -1;
1458
1459 void
1460 dissect_eigrp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
1461   e_eigrp     ih;
1462   proto_tree *eigrp_tree;
1463   proto_item *ti;
1464   guint16    cksum;
1465   gchar      type_str[64] = "";
1466
1467   /* Avoids alignment problems on many architectures. */
1468 static const value_string eigrp_opcode_vals[] = {
1469         { EIGRP_HELLO,          "Hello/Ack" },
1470         { EIGRP_UPDATE,         "Update" },
1471         { EIGRP_REPLY,          "Reply" },
1472         { EIGRP_QUERY,          "Query" },
1473         { EIGRP_REQUEST,        "Request" },
1474         { 0,                            NULL }    
1475 };
1476   
1477    memcpy(&ih, &pd[offset], sizeof(e_eigrp));
1478   /* To do: check for runts, errs, etc. */
1479   cksum = ntohs(ih.eigrp_checksum);
1480   
1481   if (check_col(fd, COL_PROTOCOL))
1482     col_add_str(fd, COL_PROTOCOL, "EIGRP");
1483   if (check_col(fd, COL_INFO))
1484     col_add_str(fd, COL_INFO, type_str);
1485   if (tree) {
1486
1487      ti = proto_tree_add_item(tree, proto_eigrp, offset, END_OF_FRAME, NULL);
1488      eigrp_tree = proto_item_add_subtree(ti, ett_eigrp);
1489   
1490      proto_tree_add_text(eigrp_tree, offset, 1, "Version: %d", ih.eigrp_version); 
1491      proto_tree_add_text(eigrp_tree, offset + 1, 1, "Opcode: %d (%s)", ih.eigrp_opcode,
1492          val_to_str( ih.eigrp_opcode, eigrp_opcode_vals, "Unknown") );
1493      proto_tree_add_text(eigrp_tree, offset + 2, 2, "Checksum: 0x%x", cksum); 
1494      proto_tree_add_text(eigrp_tree, offset + 4, 2, "Subnets in local net: %d", ih.eigrp_subnets); 
1495      proto_tree_add_text(eigrp_tree, offset + 6, 2, "Networks in Autonomous System: %d", ih.eigrp_networks); 
1496      proto_tree_add_text(eigrp_tree, offset + 8, 4, "Sequence Number: 0x%x", ih.eigrp_sequence); 
1497      proto_tree_add_text(eigrp_tree, offset + 12, 4, "Autonomous System number: %ld", ih.eigrp_asnumber); 
1498    }
1499 }
1500
1501
1502 void
1503 proto_register_eigrp(void)
1504    {
1505       static gint *ett[] = {
1506         &ett_eigrp,
1507       };
1508    proto_eigrp = proto_register_protocol("Enhanced Interior Gateway Routing Protocol", "eigrp");
1509    proto_register_subtree_array(ett, array_length(ett));
1510    }