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