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