Register "ett_gre_flags" as an subtree type.
[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.8 1999/12/08 21:38:14 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
60 static int calc_len(guint16, int);
61 static void add_flags_and_ver(proto_tree *, guint16, int, int);
62
63 void
64 dissect_gre(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
65   
66   guint16       flags_and_ver = pntohs(pd + offset);
67   guint16       type          = pntohs(pd + offset + sizeof(flags_and_ver));
68   static const value_string typevals[] = {
69     { GRE_PPP, "PPP" },
70     { 0,       NULL  }
71   };
72
73   if (check_col(fd, COL_PROTOCOL))
74     col_add_str(fd, COL_PROTOCOL, "GRE");
75         
76   if (check_col(fd, COL_INFO)) {
77     if (type == GRE_PPP)
78       col_add_str(fd, COL_INFO, "Encapsulated PPP");
79     else
80       col_add_str(fd, COL_INFO, "Encapsulated unknown");
81   }
82                 
83   if (IS_DATA_IN_FRAME(offset) && tree) {
84     int                 is_ppp;
85     proto_item *        ti;
86     proto_tree *        gre_tree;
87
88     if (type == GRE_PPP) {
89       is_ppp = 1;
90       ti = proto_tree_add_item_format(tree, proto_gre, offset, calc_len(flags_and_ver, 1),
91         NULL, "Generic Routing Encapsulation (PPP)");
92       gre_tree = proto_item_add_subtree(ti, ett_gre);
93       add_flags_and_ver(gre_tree, flags_and_ver, offset, 1);
94     }
95     else {
96       is_ppp = 0;
97       ti = proto_tree_add_item(tree, proto_gre, offset, calc_len(flags_and_ver, 1), NULL);
98       gre_tree = proto_item_add_subtree(ti, ett_gre);
99       add_flags_and_ver(gre_tree, flags_and_ver, offset, 0);
100     }
101
102     offset += sizeof(flags_and_ver);
103
104     proto_tree_add_text(gre_tree, offset, sizeof(type),
105                         "Protocol Type: %s (%#04x)",
106                         val_to_str(type, typevals, "Unknown"), type);
107     offset += sizeof(type);    
108
109     if (flags_and_ver & GH_B_C || flags_and_ver & GH_B_R) {
110       guint16 checksum = pntohs(pd + offset);
111       proto_tree_add_text(gre_tree, offset, sizeof(checksum),
112                           "Checksum: %u", checksum);
113       offset += sizeof(checksum);
114     }
115     
116     if (flags_and_ver & GH_B_C || flags_and_ver & GH_B_R) {
117       guint16 rtoffset = pntohs(pd + offset);
118       proto_tree_add_text(gre_tree, offset, sizeof(rtoffset),
119                           "Offset: %u", rtoffset);
120       offset += sizeof(rtoffset);
121     }
122
123     if (flags_and_ver & GH_B_K) {
124       if (is_ppp) {
125         guint16 paylen;
126         guint16 callid;
127         
128         paylen = pntohs(pd + offset);
129         proto_tree_add_text(gre_tree, offset, sizeof(paylen),
130                             "Payload length: %u", paylen);
131         offset += sizeof(paylen);
132
133         callid = pntohs(pd + offset);
134         proto_tree_add_text(gre_tree, offset, sizeof(callid),
135                             "Call ID: %u", callid);
136         offset += sizeof(callid);
137       }
138       else {
139         guint32 key = pntohl(pd + offset);
140         proto_tree_add_text(gre_tree, offset, sizeof(key),
141                             "Key: %u", key);
142         offset += sizeof(key);
143       }
144     }
145     
146     if (flags_and_ver & GH_B_S) {
147       guint32 seqnum = pntohl(pd + offset);
148       proto_tree_add_text(gre_tree, offset, sizeof(seqnum),
149                           "Sequence number: %u", seqnum);
150       offset += sizeof(seqnum);
151     }
152
153     if (is_ppp && flags_and_ver & GH_P_A) {
154       guint32 acknum = pntohl(pd + offset);
155       proto_tree_add_text(gre_tree, offset, sizeof(acknum),
156                           "Acknowledgement number: %u", acknum);
157       offset += sizeof(acknum);
158     }
159
160     if (flags_and_ver & GH_B_R) {
161       proto_tree_add_text(gre_tree, offset, sizeof(guint16),
162                           "Address family: %u", pntohs(pd + offset));
163       offset += sizeof(guint16);
164       proto_tree_add_text(gre_tree, offset, 1,
165                           "SRE offset: %u", pd[offset++]);
166       proto_tree_add_text(gre_tree, offset, 1,
167                           "SRE length: %u", pd[offset++]);
168     }
169
170     switch (type) {
171        case GRE_PPP:
172         dissect_payload_ppp(pd, offset, fd, tree);
173         break;
174       default:
175         dissect_data(pd, offset, fd, gre_tree);
176     }
177   }
178 }
179
180 static int
181 calc_len(guint16 flags_and_ver, int is_ppp) {
182   
183   int   len = 4;
184   
185   if (flags_and_ver & GH_B_C || flags_and_ver & GH_B_R) len += 4;
186   if (flags_and_ver & GH_B_K) len += 4;
187   if (flags_and_ver & GH_B_S) len += 4;
188   if (is_ppp && flags_and_ver & GH_P_A) len += 4;
189   
190   return len;
191 }
192
193 static void
194 add_flags_and_ver(proto_tree *tree, guint16 flags_and_ver, int offset, int is_ppp) {
195
196   proto_item *  ti;
197   proto_tree *  fv_tree;
198   int           nbits = sizeof(flags_and_ver) * 8;
199   
200   ti = proto_tree_add_text(tree, offset, 2, 
201                            "Flags and version: %#08x", flags_and_ver);
202   fv_tree = proto_item_add_subtree(ti, ett_gre_flags);
203   
204   proto_tree_add_text(fv_tree, offset, sizeof(flags_and_ver), "%s",
205                       decode_boolean_bitfield(flags_and_ver, GH_B_C, nbits,
206                                               "Checksum", "No checksum"));
207   proto_tree_add_text(fv_tree, offset, sizeof(flags_and_ver), "%s",
208                       decode_boolean_bitfield(flags_and_ver, GH_B_R, nbits,
209                                               "Routing", "No routing"));
210   proto_tree_add_text(fv_tree, offset, sizeof(flags_and_ver), "%s",
211                       decode_boolean_bitfield(flags_and_ver, GH_B_K, nbits,
212                                               "Key", "No key"));
213   proto_tree_add_text(fv_tree, offset, sizeof(flags_and_ver), "%s",
214                       decode_boolean_bitfield(flags_and_ver, GH_B_S, nbits,
215                                               "Sequence number", "No sequence number"));
216   proto_tree_add_text(fv_tree, offset, sizeof(flags_and_ver), "%s",
217                       decode_boolean_bitfield(flags_and_ver, GH_B_s, nbits,
218                                               "Strict source route", "No strict source route"));
219   proto_tree_add_text(fv_tree, offset, sizeof(flags_and_ver), "%s",
220                       decode_numeric_bitfield(flags_and_ver, GH_B_RECUR, nbits,
221                                               "Recursion control: %u"));
222   if (is_ppp) {
223     proto_tree_add_text(fv_tree, offset, sizeof(flags_and_ver), "%s",
224                         decode_boolean_bitfield(flags_and_ver, GH_P_A, nbits,
225                                                 "Acknowledgment number", "No acknowledgment number"));
226     proto_tree_add_text(fv_tree, offset, sizeof(flags_and_ver), "%s",
227                         decode_numeric_bitfield(flags_and_ver, GH_P_FLAGS, nbits,
228                                                 "Flags: %u"));
229   }
230   else {
231     proto_tree_add_text(fv_tree, offset, sizeof(flags_and_ver), "%s",
232                         decode_numeric_bitfield(flags_and_ver, GH_R_FLAGS, nbits,
233                                                 "Flags: %u"));
234   }
235
236   proto_tree_add_text(fv_tree, offset, sizeof(flags_and_ver), "%s",
237                       decode_numeric_bitfield(flags_and_ver, GH_B_VER, nbits,
238                                               "Version: %u"));
239  }
240  
241 void
242 proto_register_gre(void)
243 {
244 /*        static hf_register_info hf[] = {
245                 { &variable,
246                 { "Name",           "gre.abbreviation", TYPE, VALS_POINTER }},
247         };*/
248         static gint *ett[] = {
249                 &ett_gre,
250                 &ett_gre_flags,
251         };
252
253         proto_gre = proto_register_protocol("Generic Routing Encapsulation", "gre");
254  /*       proto_register_field_array(proto_gre, hf, array_length(hf));*/
255         proto_register_subtree_array(ett, array_length(ett));
256 }