c03d8ddcbf5b3b7f25e30ff27e23ff804b799119
[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.1 1999/06/11 15:30:37 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_item(tree, offset, calc_len(flags_and_ver, 1),
84         "Generic Routing Encapsulation (PPP)");
85       gre_tree = proto_tree_new();
86       proto_item_add_subtree(ti, gre_tree, ETT_GRE);
87       add_flags_and_ver(gre_tree, flags_and_ver, offset, 1);
88     }
89     else {
90       is_ppp = 0;
91       ti = proto_tree_add_item(tree, offset, calc_len(flags_and_ver, 1),
92         "Generic Routing Encapsulation");
93       gre_tree = proto_tree_new();
94       proto_item_add_subtree(ti, gre_tree, ETT_GRE);
95       add_flags_and_ver(gre_tree, flags_and_ver, offset, 0);
96     }
97
98     offset += sizeof(flags_and_ver);
99
100     proto_tree_add_item(gre_tree, offset, sizeof(type),
101                         "Protocol Type: %s (%#04x)",
102                         val_to_str(type, typevals, "Unknown"), type);
103     offset += sizeof(type);    
104
105     if (flags_and_ver & GH_B_C || flags_and_ver & GH_B_R) {
106       guint16 checksum = pntohs(pd + offset);
107       proto_tree_add_item(gre_tree, offset, sizeof(checksum),
108                           "Checksum: %u", checksum);
109       offset += sizeof(checksum);
110     }
111     
112     if (flags_and_ver & GH_B_C || flags_and_ver & GH_B_R) {
113       guint16 rtoffset = pntohs(pd + offset);
114       proto_tree_add_item(gre_tree, offset, sizeof(rtoffset),
115                           "Offset: %u", rtoffset);
116       offset += sizeof(rtoffset);
117     }
118
119     if (flags_and_ver & GH_B_K) {
120       if (is_ppp) {
121         guint16 paylen;
122         guint16 callid;
123         
124         paylen = pntohs(pd + offset);
125         proto_tree_add_item(gre_tree, offset, sizeof(paylen),
126                             "Payload length: %u", paylen);
127         offset += sizeof(paylen);
128
129         callid = pntohs(pd + offset);
130         proto_tree_add_item(gre_tree, offset, sizeof(callid),
131                             "Call ID: %u", callid);
132         offset += sizeof(callid);
133       }
134       else {
135         guint32 key = pntohl(pd + offset);
136         proto_tree_add_item(gre_tree, offset, sizeof(key),
137                             "Key: %u", key);
138         offset += sizeof(key);
139       }
140     }
141     
142     if (flags_and_ver & GH_B_S) {
143       guint32 seqnum = pntohl(pd + offset);
144       proto_tree_add_item(gre_tree, offset, sizeof(seqnum),
145                           "Sequence number: %u", seqnum);
146       offset += sizeof(seqnum);
147     }
148
149     if (is_ppp && flags_and_ver & GH_P_A) {
150       guint32 acknum = pntohl(pd + offset);
151       proto_tree_add_item(gre_tree, offset, sizeof(acknum),
152                           "Acknowledgement number: %u", acknum);
153       offset += sizeof(acknum);
154     }
155
156     if (flags_and_ver & GH_B_R) {
157       proto_tree_add_item(gre_tree, offset, sizeof(guint16),
158                           "Address family: %u", pntohs(pd + offset));
159       offset += sizeof(guint16);
160       proto_tree_add_item(gre_tree, offset, 1,
161                           "SRE offset: %u", pd[offset++]);
162       proto_tree_add_item(gre_tree, offset, 1,
163                           "SRE length: %u", pd[offset++]);
164     }
165
166     switch (type) {
167        case GRE_PPP:
168         dissect_payload_ppp(pd, offset, fd, tree);
169         break;
170       default:
171         dissect_data(pd, offset, fd, gre_tree);
172     }
173   }
174 }
175
176 static int
177 calc_len(guint16 flags_and_ver, int is_ppp) {
178   
179   int   len = 4;
180   
181   if (flags_and_ver & GH_B_C || flags_and_ver & GH_B_R) len += 4;
182   if (flags_and_ver & GH_B_K) len += 4;
183   if (flags_and_ver & GH_B_S) len += 4;
184   if (is_ppp && flags_and_ver & GH_P_A) len += 4;
185   
186   return len;
187 }
188
189 static void
190 add_flags_and_ver(proto_tree *tree, guint16 flags_and_ver, int offset, int is_ppp) {
191
192   proto_item *  ti;
193   proto_tree *  fv_tree;
194   int           nbits = sizeof(flags_and_ver) * 8;
195   
196   ti = proto_tree_add_item(tree, offset, 2, 
197                            "Flags and version: %#08x", flags_and_ver);
198   fv_tree = proto_tree_new();
199   proto_item_add_subtree(ti, fv_tree, ETT_GRE_FLAGS);
200   
201   proto_tree_add_item(fv_tree, offset, sizeof(flags_and_ver), "%s",
202                       decode_boolean_bitfield(flags_and_ver, GH_B_C, nbits,
203                                               "Checksum", "No checksum"));
204   proto_tree_add_item(fv_tree, offset, sizeof(flags_and_ver), "%s",
205                       decode_boolean_bitfield(flags_and_ver, GH_B_R, nbits,
206                                               "Routing", "No routing"));
207   proto_tree_add_item(fv_tree, offset, sizeof(flags_and_ver), "%s",
208                       decode_boolean_bitfield(flags_and_ver, GH_B_K, nbits,
209                                               "Key", "No key"));
210   proto_tree_add_item(fv_tree, offset, sizeof(flags_and_ver), "%s",
211                       decode_boolean_bitfield(flags_and_ver, GH_B_S, nbits,
212                                               "Sequence number", "No sequence number"));
213   proto_tree_add_item(fv_tree, offset, sizeof(flags_and_ver), "%s",
214                       decode_boolean_bitfield(flags_and_ver, GH_B_s, nbits,
215                                               "Strict source route", "No strict source route"));
216   proto_tree_add_item(fv_tree, offset, sizeof(flags_and_ver), "%s",
217                       decode_numeric_bitfield(flags_and_ver, GH_B_RECUR, nbits,
218                                               "Recursion control: %u"));
219   if (is_ppp) {
220     proto_tree_add_item(fv_tree, offset, sizeof(flags_and_ver), "%s",
221                         decode_boolean_bitfield(flags_and_ver, GH_P_A, nbits,
222                                                 "Acknowledgment number", "No acknowledgment number"));
223     proto_tree_add_item(fv_tree, offset, sizeof(flags_and_ver), "%s",
224                         decode_numeric_bitfield(flags_and_ver, GH_P_FLAGS, nbits,
225                                                 "Flags: %u"));
226   }
227   else {
228     proto_tree_add_item(fv_tree, offset, sizeof(flags_and_ver), "%s",
229                         decode_numeric_bitfield(flags_and_ver, GH_R_FLAGS, nbits,
230                                                 "Flags: %u"));
231   }
232
233   proto_tree_add_item(fv_tree, offset, sizeof(flags_and_ver), "%s",
234                       decode_numeric_bitfield(flags_and_ver, GH_B_VER, nbits,
235                                               "Version: %u"));
236  }
237