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