For proto_tree_add_item(..., proto_xxx, ...)use ENC_NA as the encoding arg.
[obnox/wireshark/wip.git] / epan / dissectors / packet-cisco-erspan.c
1 /* packet-erspan.c
2  * Routines for the disassembly of Cisco's ERSPAN protocol
3  *
4  * $Id$
5  *
6  * Copyright 2005 Joerg Mayer (see AUTHORS file)
7  * Updates for newer versions by Jason Masker <jason at masker.net>
8  *
9  * Wireshark - Network traffic analyzer
10  * By Gerald Combs <gerald@wireshark.org>
11  * Copyright 1998 Gerald Combs
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  */
27
28 /*
29  * TODO:
30  *      Find out the Unknown values
31  *
32  * Specs:
33  *      No real specs exist. Some general description can be found at:
34  *      http://www.cisco.com/en/US/products/hw/routers/ps368/products_configuration_guide_chapter09186a008069952a.html
35  *
36  *      Some information on ERSPAN type III can be found at:
37  *      http://www.cisco.com/en/US/docs/switches/datacenter/nexus1000/sw/4_0_4_s_v_1_3/system_management/configuration/guide/n1000v_system_9span.html
38  *
39  *      For ERSPAN packets, the "protocol type" field value in the GRE header
40  *      is 0x88BE (version 1) or 0x22EB (version 2).
41  *
42  *      ERSPAN type II is version 1
43  *      ERSPAN type III is version 2
44  *
45  * 0000000: d4c3 b2a1 0200 0400 0000 0000 0000 0000 <-- pcap header
46  * 0000010: ffff 0000
47  * 0000010:           7100 0000 <-- 0x71 (DLT_TYPE) = linux_cooked_capture (of course not)
48  * 0000010:                     7507 f845 11d1 0500 <-- pcap record header
49  * 0000020: 7a00 0000 7a00 0000
50  * 0000020:                     0000 030a 0000 0000 <-- unknown
51  * 0000030: 0000 0000
52  * 0000030:           0000 88be <-- GRE header (version 1)
53  * 0000030:                     1002 0001 0000 0380 <-- ERSPAN header (01: erspan-id)
54  * 0000040: 00d0 b7a7 7480 0015 c721 75c0 0800 4500 <-- Ethernet packet
55  * ...
56  *
57  *
58  */
59
60 #ifdef HAVE_CONFIG_H
61 #  include "config.h"
62 #endif
63
64 #include <glib.h>
65 #include <epan/packet.h>
66 #include <epan/greproto.h>
67
68 static int proto_erspan = -1;
69
70 static gint ett_erspan = -1;
71
72 static int hf_erspan_version = -1;
73 static int hf_erspan_vlan = -1;
74 static int hf_erspan_priority = -1;
75 static int hf_erspan_unknown2 = -1;
76 static int hf_erspan_direction = -1;
77 static int hf_erspan_unknown3 = -1;
78 static int hf_erspan_truncated = -1;
79 static int hf_erspan_spanid = -1;
80 static int hf_erspan_timestamp = -1;
81 static int hf_erspan_unknown4 = -1;
82 static int hf_erspan_direction2 = -1;
83 static int hf_erspan_unknown5 = -1;
84 static int hf_erspan_unknown6 = -1;
85 static int hf_erspan_unknown7 = -1;
86
87 #define PROTO_SHORT_NAME "ERSPAN"
88 #define PROTO_LONG_NAME "Encapsulated Remote Switch Packet ANalysis"
89
90 #define ERSPAN_DIRECTION_INCOMING 0
91 #define ERSPAN_DIRECTION_OUTGOING 1
92 static const value_string erspan_direction_vals[] = {
93         {ERSPAN_DIRECTION_INCOMING, "Incoming"},
94         {ERSPAN_DIRECTION_OUTGOING, "Outgoing"},
95         {0, NULL},
96 };
97
98 static const value_string erspan_truncated_vals[] = {
99         {0, "Not truncated"},
100         {1, "Trunkated"},
101         {0, NULL},
102 };
103
104 static const value_string erspan_version_vals[] = {
105         {1, "Type II"},
106         {2, "Type III"},
107         {0, NULL},
108 };
109
110 static dissector_handle_t ethnofcs_handle;
111
112 static void
113 erspan_fmt_timestamp(gchar *result, guint32 timeval)
114 {
115         g_snprintf(result, ITEM_LABEL_LENGTH, "%.4f", (((gfloat)timeval)/10000));
116 }
117
118 static void
119 dissect_erspan(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
120 {
121         proto_item *ti;
122         proto_item *unknown_version;
123         proto_tree *erspan_tree = NULL;
124         tvbuff_t *eth_tvb;
125         guint32 offset = 0;
126         guint16 version = 0;
127
128         col_set_str(pinfo->cinfo, COL_PROTOCOL, PROTO_SHORT_NAME);
129         col_set_str(pinfo->cinfo, COL_INFO, PROTO_SHORT_NAME ":");
130
131         if (tree) {
132                 ti = proto_tree_add_item(tree, proto_erspan, tvb, offset, -1,
133                     ENC_NA);
134                 erspan_tree = proto_item_add_subtree(ti, ett_erspan);
135
136                 version = tvb_get_ntohs(tvb, offset) >> 12;
137                 proto_tree_add_item(erspan_tree, hf_erspan_version, tvb, offset, 2,
138                         ENC_BIG_ENDIAN);
139                 if ((version != 1) && (version != 2 )) {
140                         unknown_version = proto_tree_add_text(erspan_tree, tvb, 0, 0,
141                                 "Unknown version, please report");
142                         PROTO_ITEM_SET_GENERATED(unknown_version);
143                         return;
144                 }
145                 proto_tree_add_item(erspan_tree, hf_erspan_vlan, tvb, offset, 2,
146                         ENC_BIG_ENDIAN);
147                 offset += 2;
148
149                 proto_tree_add_item(erspan_tree, hf_erspan_priority, tvb, offset, 2,
150                         ENC_BIG_ENDIAN);
151                 proto_tree_add_item(erspan_tree, hf_erspan_unknown2, tvb, offset, 2,
152                         ENC_BIG_ENDIAN);
153                 if (version == 1)
154                         proto_tree_add_item(erspan_tree, hf_erspan_direction, tvb,
155                                 offset, 2, ENC_BIG_ENDIAN);
156                 else /* version = 2 */
157                         proto_tree_add_item(erspan_tree, hf_erspan_unknown3, tvb,
158                                 offset, 2, ENC_BIG_ENDIAN);
159                 proto_tree_add_item(erspan_tree, hf_erspan_truncated, tvb, offset, 2,
160                         ENC_BIG_ENDIAN);
161                 proto_tree_add_item(erspan_tree, hf_erspan_spanid, tvb, offset, 2,
162                         ENC_BIG_ENDIAN);
163                 offset += 2;
164
165                 if (version == 2) {
166                         proto_tree_add_item(erspan_tree, hf_erspan_timestamp, tvb,
167                                 offset, 4, ENC_BIG_ENDIAN);
168                         offset += 4;
169
170                         proto_tree_add_item(erspan_tree, hf_erspan_unknown4, tvb,
171                                 offset, 2, ENC_NA);
172                         offset += 2;
173
174                         proto_tree_add_item(erspan_tree, hf_erspan_direction2, tvb,
175                                 offset, 2, ENC_BIG_ENDIAN);
176                         proto_tree_add_item(erspan_tree, hf_erspan_unknown5, tvb,
177                                 offset, 2, ENC_BIG_ENDIAN);
178                         offset += 2;
179
180                         proto_tree_add_item(erspan_tree, hf_erspan_unknown6, tvb,
181                                 offset, 4, ENC_NA);
182                         offset += 4;
183                 }
184                 proto_tree_add_item(erspan_tree, hf_erspan_unknown7, tvb, offset, 4,
185                         ENC_NA);
186                 offset += 4;
187         }
188         else {
189                 offset += 8;
190                 if (version == 2)
191                         offset += 12;
192         }
193
194         eth_tvb = tvb_new_subset_remaining(tvb, offset);
195         call_dissector(ethnofcs_handle, eth_tvb, pinfo, tree);
196 }
197
198 void
199 proto_register_erspan(void)
200 {
201         static hf_register_info hf[] = {
202
203                 { &hf_erspan_version,
204                 { "Version",    "erspan.version", FT_UINT16, BASE_DEC, VALS(erspan_version_vals),
205                         0xf000, NULL, HFILL }},
206
207                 { &hf_erspan_vlan,
208                 { "Vlan",       "erspan.vlan", FT_UINT16, BASE_DEC, NULL,
209                         0x0fff, NULL, HFILL }},
210
211                 { &hf_erspan_priority,
212                 { "Priority",   "erspan.priority", FT_UINT16, BASE_DEC, NULL,
213                         0xe000, NULL, HFILL }},
214
215                 { &hf_erspan_unknown2,
216                 { "Unknown2",   "erspan.unknown2", FT_UINT16, BASE_DEC, NULL,
217                         0x1000, NULL, HFILL }},
218
219                 { &hf_erspan_direction,
220                 { "Direction",  "erspan.direction", FT_UINT16, BASE_DEC, VALS(erspan_direction_vals),
221                         0x0800, NULL, HFILL }},
222
223                 { &hf_erspan_unknown3,
224                 { "Unknown3",   "erspan.unknown3", FT_UINT16, BASE_DEC, NULL,
225                         0x0800, NULL, HFILL }},
226
227                 { &hf_erspan_truncated,
228                 { "Truncated",  "erspan.truncated", FT_UINT16, BASE_DEC, VALS(erspan_truncated_vals),
229                         0x0400, "ERSPAN packet exceeded the MTU size", HFILL }},
230
231                 { &hf_erspan_spanid,
232                 { "SpanID",     "erspan.spanid", FT_UINT16, BASE_DEC, NULL,
233                         0x03ff, NULL, HFILL }},
234
235                 { &hf_erspan_timestamp,
236                 { "Timestamp",  "erspan.timestamp", FT_UINT32, BASE_CUSTOM, erspan_fmt_timestamp,
237                         0, NULL, HFILL }},
238
239                 { &hf_erspan_unknown4,
240                 { "Unknown4",   "erspan.unknown4", FT_BYTES, BASE_NONE, NULL,
241                         0, NULL, HFILL }},
242
243                 { &hf_erspan_direction2,
244                 { "Direction2", "erspan.direction2", FT_UINT16, BASE_DEC, VALS(erspan_direction_vals),
245                         0x0008, NULL, HFILL }},
246
247                 { &hf_erspan_unknown5,
248                 { "Unknown5",   "erspan.unknown5", FT_UINT16, BASE_HEX, NULL,
249                         0xfff7, NULL, HFILL }},
250
251                 { &hf_erspan_unknown6,
252                 { "Unknown6",   "erspan.unknown6", FT_BYTES, BASE_NONE, NULL,
253                         0, NULL, HFILL }},
254
255                 { &hf_erspan_unknown7,
256                 { "Unknown7",   "erspan.unknown7", FT_BYTES, BASE_NONE, NULL,
257                         0, NULL, HFILL }},
258
259         };
260         static gint *ett[] = {
261                 &ett_erspan,
262         };
263
264         proto_erspan = proto_register_protocol(PROTO_LONG_NAME,
265             PROTO_SHORT_NAME, "erspan");
266         proto_register_field_array(proto_erspan, hf, array_length(hf));
267         proto_register_subtree_array(ett, array_length(ett));
268 }
269
270 void
271 proto_reg_handoff_erspan(void)
272 {
273         dissector_handle_t erspan_handle;
274
275         ethnofcs_handle = find_dissector("eth_withoutfcs");
276
277         erspan_handle = create_dissector_handle(dissect_erspan, proto_erspan);
278         dissector_add_uint("gre.proto", GRE_ERSPAN_88BE, erspan_handle);
279         dissector_add_uint("gre.proto", GRE_ERSPAN_22EB, erspan_handle);
280
281 }
282