Don't do "if this is PPP, do this, else do that" quite so much - use
[obnox/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.11 1999/12/10 21:27:13 guy 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 #ifdef HAVE_NETINET_IN_H
36 #include <netinet/in.h>
37 #endif
38 #include <glib.h>
39 #include "packet.h"
40
41 static int proto_gre = -1;
42
43 static gint ett_gre = -1;
44 static gint ett_gre_flags = -1;
45
46 /* bit positions for flags in header */
47 #define GH_B_C          0x8000
48 #define GH_B_R          0x4000
49 #define GH_B_K          0x2000
50 #define GH_B_S          0x1000
51 #define GH_B_s          0x0800
52 #define GH_B_RECUR      0x0700
53 #define GH_P_A          0x0080  /* only in special PPTPized GRE header */
54 #define GH_P_FLAGS      0x0078  /* only in special PPTPized GRE header */
55 #define GH_R_FLAGS      0x00F8
56 #define GH_B_VER        0x0007
57
58 #define GRE_PPP         0x880B
59 #define GRE_IP          0x0800
60
61 static int calc_len(guint16, int);
62 static void add_flags_and_ver(proto_tree *, guint16, int, int);
63
64 void
65 dissect_gre(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
66   
67   guint16       flags_and_ver = pntohs(pd + offset);
68   guint16       type          = pntohs(pd + offset + sizeof(flags_and_ver));
69   static const value_string typevals[] = {
70     { GRE_PPP, "PPP" },
71     { GRE_IP,  "IP" },
72     { 0,       NULL  }
73   };
74   guint16       sre_af;
75   guint8        sre_length;
76
77   if (check_col(fd, COL_PROTOCOL))
78     col_add_str(fd, COL_PROTOCOL, "GRE");
79         
80   if (check_col(fd, COL_INFO)) {
81     col_add_fstr(fd, COL_INFO, "Encapsulated %s",
82         val_to_str(type, typevals, "0x%04X (unknown)"));
83   }
84                 
85   if (IS_DATA_IN_FRAME(offset) && tree) {
86     gboolean            is_ppp;
87     proto_item *        ti;
88     proto_tree *        gre_tree;
89
90     is_ppp = (type == GRE_PPP);
91
92     ti = proto_tree_add_item_format(tree, proto_gre, offset,
93       calc_len(flags_and_ver, type), NULL,
94       "Generic Routing Encapsulation (%s)",
95       val_to_str(type, typevals, "0x%04X - unknown"));
96     gre_tree = proto_item_add_subtree(ti, ett_gre);
97     add_flags_and_ver(gre_tree, flags_and_ver, offset, is_ppp);
98
99     offset += sizeof(flags_and_ver);
100
101     proto_tree_add_text(gre_tree, offset, sizeof(type),
102                         "Protocol Type: %s (%#04x)",
103                         val_to_str(type, typevals, "Unknown"), type);
104     offset += sizeof(type);    
105
106     if (flags_and_ver & GH_B_C || flags_and_ver & GH_B_R) {
107       guint16 checksum = pntohs(pd + offset);
108       proto_tree_add_text(gre_tree, offset, sizeof(checksum),
109                           "Checksum: %u", checksum);
110       offset += sizeof(checksum);
111     }
112     
113     if (flags_and_ver & GH_B_C || flags_and_ver & GH_B_R) {
114       guint16 rtoffset = pntohs(pd + offset);
115       proto_tree_add_text(gre_tree, offset, sizeof(rtoffset),
116                           "Offset: %u", rtoffset);
117       offset += sizeof(rtoffset);
118     }
119
120     if (flags_and_ver & GH_B_K) {
121       if (is_ppp) {
122         guint16 paylen;
123         guint16 callid;
124         
125         paylen = pntohs(pd + offset);
126         proto_tree_add_text(gre_tree, offset, sizeof(paylen),
127                             "Payload length: %u", paylen);
128         offset += sizeof(paylen);
129
130         callid = pntohs(pd + offset);
131         proto_tree_add_text(gre_tree, offset, sizeof(callid),
132                             "Call ID: %u", callid);
133         offset += sizeof(callid);
134       }
135       else {
136         guint32 key = pntohl(pd + offset);
137         proto_tree_add_text(gre_tree, offset, sizeof(key),
138                             "Key: %u", key);
139         offset += sizeof(key);
140       }
141     }
142     
143     if (flags_and_ver & GH_B_S) {
144       guint32 seqnum = pntohl(pd + offset);
145       proto_tree_add_text(gre_tree, offset, sizeof(seqnum),
146                           "Sequence number: %u", seqnum);
147       offset += sizeof(seqnum);
148     }
149
150     if (is_ppp && flags_and_ver & GH_P_A) {
151       guint32 acknum = pntohl(pd + offset);
152       proto_tree_add_text(gre_tree, offset, sizeof(acknum),
153                           "Acknowledgement number: %u", acknum);
154       offset += sizeof(acknum);
155     }
156
157     if (flags_and_ver & GH_B_R) {
158       for (;;) {
159         sre_af = pntohs(pd + offset);
160         proto_tree_add_text(gre_tree, offset, sizeof(guint16),
161                           "Address family: %u", sre_af);
162         offset += sizeof(guint16);
163         proto_tree_add_text(gre_tree, offset, 1,
164                           "SRE offset: %u", pd[offset++]);
165         sre_length = pd[offset];
166         proto_tree_add_text(gre_tree, offset, sizeof(guint8),
167                           "SRE length: %u", sre_length);
168         offset += sizeof(guint8);
169         if (sre_af == 0 && sre_length == 0)
170           break;
171         offset += sre_length;
172       }
173     }
174
175     switch (type) {
176       case GRE_PPP:
177         dissect_payload_ppp(pd, offset, fd, tree);
178         break;
179       case GRE_IP:
180         dissect_ip(pd, offset, fd, tree);
181         break;
182       default:
183         dissect_data(pd, offset, fd, gre_tree);
184     }
185   }
186 }
187
188 static int
189 calc_len(guint16 flags_and_ver, int type)
190 {
191   int   len = 4;
192   
193   if (flags_and_ver & GH_B_C || flags_and_ver & GH_B_R)
194     len += 4;
195   if (flags_and_ver & GH_B_K)
196     len += 4;
197   if (flags_and_ver & GH_B_S)
198     len += 4;
199   switch (type) {
200
201   case GRE_PPP:
202     if (flags_and_ver & GH_P_A)
203       len += 4;
204     break;
205   }
206   
207   return len;
208 }
209
210 static void
211 add_flags_and_ver(proto_tree *tree, guint16 flags_and_ver, int offset, int is_ppp) {
212
213   proto_item *  ti;
214   proto_tree *  fv_tree;
215   int           nbits = sizeof(flags_and_ver) * 8;
216   
217   ti = proto_tree_add_text(tree, offset, 2, 
218                            "Flags and version: %#04x", flags_and_ver);
219   fv_tree = proto_item_add_subtree(ti, ett_gre_flags);
220   
221   proto_tree_add_text(fv_tree, offset, sizeof(flags_and_ver), "%s",
222                       decode_boolean_bitfield(flags_and_ver, GH_B_C, nbits,
223                                               "Checksum", "No checksum"));
224   proto_tree_add_text(fv_tree, offset, sizeof(flags_and_ver), "%s",
225                       decode_boolean_bitfield(flags_and_ver, GH_B_R, nbits,
226                                               "Routing", "No routing"));
227   proto_tree_add_text(fv_tree, offset, sizeof(flags_and_ver), "%s",
228                       decode_boolean_bitfield(flags_and_ver, GH_B_K, nbits,
229                                               "Key", "No key"));
230   proto_tree_add_text(fv_tree, offset, sizeof(flags_and_ver), "%s",
231                       decode_boolean_bitfield(flags_and_ver, GH_B_S, nbits,
232                                               "Sequence number", "No sequence number"));
233   proto_tree_add_text(fv_tree, offset, sizeof(flags_and_ver), "%s",
234                       decode_boolean_bitfield(flags_and_ver, GH_B_s, nbits,
235                                               "Strict source route", "No strict source route"));
236   proto_tree_add_text(fv_tree, offset, sizeof(flags_and_ver), "%s",
237                       decode_numeric_bitfield(flags_and_ver, GH_B_RECUR, nbits,
238                                               "Recursion control: %u"));
239   if (is_ppp) {
240     proto_tree_add_text(fv_tree, offset, sizeof(flags_and_ver), "%s",
241                         decode_boolean_bitfield(flags_and_ver, GH_P_A, nbits,
242                                                 "Acknowledgment number", "No acknowledgment number"));
243     proto_tree_add_text(fv_tree, offset, sizeof(flags_and_ver), "%s",
244                         decode_numeric_bitfield(flags_and_ver, GH_P_FLAGS, nbits,
245                                                 "Flags: %u"));
246   }
247   else {
248     proto_tree_add_text(fv_tree, offset, sizeof(flags_and_ver), "%s",
249                         decode_numeric_bitfield(flags_and_ver, GH_R_FLAGS, nbits,
250                                                 "Flags: %u"));
251   }
252
253   proto_tree_add_text(fv_tree, offset, sizeof(flags_and_ver), "%s",
254                       decode_numeric_bitfield(flags_and_ver, GH_B_VER, nbits,
255                                               "Version: %u"));
256  }
257  
258 void
259 proto_register_gre(void)
260 {
261 /*        static hf_register_info hf[] = {
262                 { &variable,
263                 { "Name",           "gre.abbreviation", TYPE, VALS_POINTER }},
264         };*/
265         static gint *ett[] = {
266                 &ett_gre,
267                 &ett_gre_flags,
268         };
269
270         proto_gre = proto_register_protocol("Generic Routing Encapsulation", "gre");
271  /*       proto_register_field_array(proto_gre, hf, array_length(hf));*/
272         proto_register_subtree_array(ett, array_length(ett));
273 }