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