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