Created a new protocol tree implementation and a new display filter
[metze/wireshark/wip.git] / packet-gre.c
1 /* packet-gre.c
2  * Routines for the Generic Routing Encapsulation (GRE) protocol
3  * Brad Robel-Forrest <brad.robel-forrest@watchguard.com>
4  *
5  * $Id: packet-gre.c,v 1.2 1999/07/07 22:51:43 gram Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@unicom.net>
9  * Copyright 1998 Gerald Combs
10  *
11  * 
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  * 
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  * 
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #ifdef HAVE_SYS_TYPES_H
32 # include <sys/types.h>
33 #endif
34
35 #include <netinet/in.h>
36 #include <glib.h>
37 #include "packet.h"
38
39 /* bit positions for flags in header */
40 #define GH_B_C          0x8000
41 #define GH_B_R          0x4000
42 #define GH_B_K          0x2000
43 #define GH_B_S          0x1000
44 #define GH_B_s          0x0800
45 #define GH_B_RECUR      0x0700
46 #define GH_P_A          0x0080  /* only in special PPTPized GRE header */
47 #define GH_P_FLAGS      0x0078  /* only in special PPTPized GRE header */
48 #define GH_R_FLAGS      0x00F8
49 #define GH_B_VER        0x0007
50
51 #define GRE_PPP         0x880B
52
53 static int calc_len(guint16, int);
54 static void add_flags_and_ver(proto_tree *, guint16, int, int);
55
56 void
57 dissect_gre(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
58   
59   guint16       flags_and_ver = pntohs(pd + offset);
60   guint16       type          = pntohs(pd + offset + sizeof(flags_and_ver));
61   static const value_string typevals[] = {
62     { GRE_PPP, "PPP" },
63     { 0,       NULL  }
64   };
65
66   if (check_col(fd, COL_PROTOCOL))
67     col_add_str(fd, COL_PROTOCOL, "GRE");
68         
69   if (check_col(fd, COL_INFO)) {
70     if (type == GRE_PPP)
71       col_add_str(fd, COL_INFO, "Encapsulated PPP");
72     else
73       col_add_str(fd, COL_INFO, "Encapsulated unknown");
74   }
75                 
76   if (fd->cap_len > offset && tree) {
77     int                 is_ppp;
78     proto_item *        ti;
79     proto_tree *        gre_tree;
80
81     if (type == GRE_PPP) {
82       is_ppp = 1;
83       ti = proto_tree_add_text(tree, offset, calc_len(flags_and_ver, 1),
84         "Generic Routing Encapsulation (PPP)");
85       gre_tree = proto_item_add_subtree(ti, ETT_GRE);
86       add_flags_and_ver(gre_tree, flags_and_ver, offset, 1);
87     }
88     else {
89       is_ppp = 0;
90       ti = proto_tree_add_text(tree, offset, calc_len(flags_and_ver, 1),
91         "Generic Routing Encapsulation");
92       gre_tree = proto_item_add_subtree(ti, ETT_GRE);
93       add_flags_and_ver(gre_tree, flags_and_ver, offset, 0);
94     }
95
96     offset += sizeof(flags_and_ver);
97
98     proto_tree_add_text(gre_tree, offset, sizeof(type),
99                         "Protocol Type: %s (%#04x)",
100                         val_to_str(type, typevals, "Unknown"), type);
101     offset += sizeof(type);    
102
103     if (flags_and_ver & GH_B_C || flags_and_ver & GH_B_R) {
104       guint16 checksum = pntohs(pd + offset);
105       proto_tree_add_text(gre_tree, offset, sizeof(checksum),
106                           "Checksum: %u", checksum);
107       offset += sizeof(checksum);
108     }
109     
110     if (flags_and_ver & GH_B_C || flags_and_ver & GH_B_R) {
111       guint16 rtoffset = pntohs(pd + offset);
112       proto_tree_add_text(gre_tree, offset, sizeof(rtoffset),
113                           "Offset: %u", rtoffset);
114       offset += sizeof(rtoffset);
115     }
116
117     if (flags_and_ver & GH_B_K) {
118       if (is_ppp) {
119         guint16 paylen;
120         guint16 callid;
121         
122         paylen = pntohs(pd + offset);
123         proto_tree_add_text(gre_tree, offset, sizeof(paylen),
124                             "Payload length: %u", paylen);
125         offset += sizeof(paylen);
126
127         callid = pntohs(pd + offset);
128         proto_tree_add_text(gre_tree, offset, sizeof(callid),
129                             "Call ID: %u", callid);
130         offset += sizeof(callid);
131       }
132       else {
133         guint32 key = pntohl(pd + offset);
134         proto_tree_add_text(gre_tree, offset, sizeof(key),
135                             "Key: %u", key);
136         offset += sizeof(key);
137       }
138     }
139     
140     if (flags_and_ver & GH_B_S) {
141       guint32 seqnum = pntohl(pd + offset);
142       proto_tree_add_text(gre_tree, offset, sizeof(seqnum),
143                           "Sequence number: %u", seqnum);
144       offset += sizeof(seqnum);
145     }
146
147     if (is_ppp && flags_and_ver & GH_P_A) {
148       guint32 acknum = pntohl(pd + offset);
149       proto_tree_add_text(gre_tree, offset, sizeof(acknum),
150                           "Acknowledgement number: %u", acknum);
151       offset += sizeof(acknum);
152     }
153
154     if (flags_and_ver & GH_B_R) {
155       proto_tree_add_text(gre_tree, offset, sizeof(guint16),
156                           "Address family: %u", pntohs(pd + offset));
157       offset += sizeof(guint16);
158       proto_tree_add_text(gre_tree, offset, 1,
159                           "SRE offset: %u", pd[offset++]);
160       proto_tree_add_text(gre_tree, offset, 1,
161                           "SRE length: %u", pd[offset++]);
162     }
163
164     switch (type) {
165        case GRE_PPP:
166         dissect_payload_ppp(pd, offset, fd, tree);
167         break;
168       default:
169         dissect_data(pd, offset, fd, gre_tree);
170     }
171   }
172 }
173
174 static int
175 calc_len(guint16 flags_and_ver, int is_ppp) {
176   
177   int   len = 4;
178   
179   if (flags_and_ver & GH_B_C || flags_and_ver & GH_B_R) len += 4;
180   if (flags_and_ver & GH_B_K) len += 4;
181   if (flags_and_ver & GH_B_S) len += 4;
182   if (is_ppp && flags_and_ver & GH_P_A) len += 4;
183   
184   return len;
185 }
186
187 static void
188 add_flags_and_ver(proto_tree *tree, guint16 flags_and_ver, int offset, int is_ppp) {
189
190   proto_item *  ti;
191   proto_tree *  fv_tree;
192   int           nbits = sizeof(flags_and_ver) * 8;
193   
194   ti = proto_tree_add_text(tree, offset, 2, 
195                            "Flags and version: %#08x", flags_and_ver);
196   fv_tree = proto_item_add_subtree(ti, ETT_GRE_FLAGS);
197   
198   proto_tree_add_text(fv_tree, offset, sizeof(flags_and_ver), "%s",
199                       decode_boolean_bitfield(flags_and_ver, GH_B_C, nbits,
200                                               "Checksum", "No checksum"));
201   proto_tree_add_text(fv_tree, offset, sizeof(flags_and_ver), "%s",
202                       decode_boolean_bitfield(flags_and_ver, GH_B_R, nbits,
203                                               "Routing", "No routing"));
204   proto_tree_add_text(fv_tree, offset, sizeof(flags_and_ver), "%s",
205                       decode_boolean_bitfield(flags_and_ver, GH_B_K, nbits,
206                                               "Key", "No key"));
207   proto_tree_add_text(fv_tree, offset, sizeof(flags_and_ver), "%s",
208                       decode_boolean_bitfield(flags_and_ver, GH_B_S, nbits,
209                                               "Sequence number", "No sequence number"));
210   proto_tree_add_text(fv_tree, offset, sizeof(flags_and_ver), "%s",
211                       decode_boolean_bitfield(flags_and_ver, GH_B_s, nbits,
212                                               "Strict source route", "No strict source route"));
213   proto_tree_add_text(fv_tree, offset, sizeof(flags_and_ver), "%s",
214                       decode_numeric_bitfield(flags_and_ver, GH_B_RECUR, nbits,
215                                               "Recursion control: %u"));
216   if (is_ppp) {
217     proto_tree_add_text(fv_tree, offset, sizeof(flags_and_ver), "%s",
218                         decode_boolean_bitfield(flags_and_ver, GH_P_A, nbits,
219                                                 "Acknowledgment number", "No acknowledgment number"));
220     proto_tree_add_text(fv_tree, offset, sizeof(flags_and_ver), "%s",
221                         decode_numeric_bitfield(flags_and_ver, GH_P_FLAGS, nbits,
222                                                 "Flags: %u"));
223   }
224   else {
225     proto_tree_add_text(fv_tree, offset, sizeof(flags_and_ver), "%s",
226                         decode_numeric_bitfield(flags_and_ver, GH_R_FLAGS, nbits,
227                                                 "Flags: %u"));
228   }
229
230   proto_tree_add_text(fv_tree, offset, sizeof(flags_and_ver), "%s",
231                       decode_numeric_bitfield(flags_and_ver, GH_B_VER, nbits,
232                                               "Version: %u"));
233  }
234