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