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