cfa247a498fa112a37b02e521fc5d51f39b8d386
[obnox/wireshark/wip.git] / epan / dissectors / packet-trill.c
1 /* packet-trill.c
2  * Routines for TRILL (TRansparent Interconnection of Lots of Links) dissection
3  * Copyright 2010, David Bond <mokon@mokon.net>
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License along
22  * with this program; if not, write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA.
24  */
25
26 /*
27  * See: http://tools.ietf.org/html/draft-ietf-trill-rbridge-protocol-16
28  */
29
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33
34 #include <glib.h>
35 #include <epan/packet.h>
36 #include <epan/etypes.h>
37
38 static int proto_trill = -1 ;
39 static gint ett_trill = -1 ;
40
41 static int hf_trill_version = -1 ;
42 static int hf_trill_reserved = -1 ;
43 static int hf_trill_multi_dst = -1 ;
44 static int hf_trill_op_len = -1 ;
45 static int hf_trill_hop_cnt = -1 ;
46 static int hf_trill_egress_nick = -1 ;
47 static int hf_trill_ingress_nick = -1 ;
48 /* TODO For now we will just add all the options into a byte field.
49    Later this should be parsed out into a sub-tree with all the option
50    details. */
51 static int hf_trill_options= -1 ; 
52
53 static dissector_handle_t eth_dissector ;
54
55 #define TRILL_VERSION_MASK 0xC000
56 #define TRILL_RESERVED_MASK 0x3000
57 #define TRILL_MULTI_DST_MASK 0x0800
58 #define TRILL_OP_LEN_MASK 0x07C0
59 #define TRILL_HOP_CNT_MASK 0x003F
60
61 #define TRILL_PROTO_COL_NAME "TRILL"
62 #define TRILL_PROTO_COL_INFO "TRILL Encapsulated Frame"
63
64 #define TRILL_MIN_FRAME_LENGTH 6
65 #define TRILL_BIT_FIELDS_LEN 2
66 #define TRILL_NICKNAME_LEN 2
67 #define TRILL_OP_LENGTH_BYTE_UNITS 0x4
68
69 static const true_false_string multi_dst_strings = {
70   "Multi-Destination TRILL Frame",
71   "Known Unicast TRILL Frame"
72 } ;
73
74 static const range_string version_strings[] = {
75   { 0, 0, "draft-ietf-trill-rbridge-protocol-16 Version" },
76   { 1, 3, "Unallocated Version" },
77   { 0, 0, NULL }
78 } ;
79
80 static const range_string reserved_strings[] = {
81   { 0, 0, "Legal Value" },
82   { 1, 3, "Illegal Value" },
83   { 0, 0, NULL }
84 } ;
85
86 static const range_string nickname_strings[] = {
87   { 0x0000, 0x0000, "Nickname Not Specified" },
88   { 0x0001, 0xFFBF, "Valid Nickname" },
89   { 0xFFC0, 0xFFFE, "Reserved for Future Specification" },
90   { 0xFFFF, 0xFFFF, "Permanently Reserved" },
91   { 0, 0, NULL }
92 } ;
93
94 /* Trill Dissector */
95 static int
96 dissect_trill( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree )
97 {
98   proto_item *ti ;
99   proto_tree *trill_tree ;
100   guint32 op_len ;
101   tvbuff_t *next_tvb ;
102   int offset = 0 ;
103
104   col_set_str( pinfo->cinfo, COL_PROTOCOL, TRILL_PROTO_COL_NAME ) ;
105   col_set_str( pinfo->cinfo, COL_INFO, TRILL_PROTO_COL_INFO ) ;
106
107   op_len = tvb_get_bits( tvb, 5, 5, FALSE ) * TRILL_OP_LENGTH_BYTE_UNITS ;
108   if (tree) {
109     ti = proto_tree_add_item( tree, proto_trill, tvb, 0, -1, FALSE ) ;
110     trill_tree = proto_item_add_subtree( ti, ett_trill ) ;
111
112     /* Parse the bit fields, i.e. V, R, M, Op-Length, Hop Count. */
113     proto_tree_add_item( trill_tree, hf_trill_version, tvb, offset,
114       TRILL_BIT_FIELDS_LEN, ENC_BIG_ENDIAN ) ;
115     proto_tree_add_item( trill_tree, hf_trill_reserved, tvb, offset,
116       TRILL_BIT_FIELDS_LEN, ENC_BIG_ENDIAN ) ;
117     proto_tree_add_item( trill_tree, hf_trill_multi_dst, tvb, offset,
118       TRILL_BIT_FIELDS_LEN, ENC_BIG_ENDIAN ) ;
119     proto_tree_add_item( trill_tree, hf_trill_op_len, tvb, offset,
120       TRILL_BIT_FIELDS_LEN, ENC_BIG_ENDIAN ) ;  
121     proto_tree_add_item( trill_tree, hf_trill_hop_cnt, tvb, offset,
122       TRILL_BIT_FIELDS_LEN, ENC_BIG_ENDIAN ) ;
123
124     /* Parse the egress nickname. */
125     offset += TRILL_BIT_FIELDS_LEN ;
126     proto_tree_add_item( trill_tree, hf_trill_egress_nick, tvb, offset,
127       TRILL_NICKNAME_LEN, ENC_BIG_ENDIAN ) ;
128
129     /* Parse the ingress nickname. */
130     offset += TRILL_NICKNAME_LEN  ;
131     proto_tree_add_item( trill_tree, hf_trill_ingress_nick, tvb, offset,
132       TRILL_NICKNAME_LEN , ENC_BIG_ENDIAN ) ;
133
134     /* Parse the options field. */
135     offset += TRILL_NICKNAME_LEN  ;
136     if( op_len != 0 ) {    
137       proto_tree_add_item( trill_tree, hf_trill_options, tvb,
138         offset, op_len, ENC_NA ) ;
139     }
140   }
141
142   /* call the eth dissector */
143   next_tvb = tvb_new_subset( tvb, TRILL_MIN_FRAME_LENGTH + op_len , -1, -1 ) ;
144   call_dissector( eth_dissector, next_tvb, pinfo, tree ) ;
145
146   return tvb_length( tvb ) ;
147 }
148
149 /* Register the protocol with Wireshark */
150 void
151 proto_register_trill(void)
152 {  
153   static hf_register_info hf[] = {
154     { &hf_trill_version,
155       { "Version", "trill.version",
156         FT_UINT16, BASE_DEC_HEX|BASE_RANGE_STRING, RVALS(version_strings),
157         TRILL_VERSION_MASK, "The TRILL version number.", HFILL }},
158     { &hf_trill_reserved,
159       { "Reserved", "trill.reserved",
160         FT_UINT16, BASE_DEC_HEX|BASE_RANGE_STRING, RVALS(reserved_strings),
161         TRILL_RESERVED_MASK, "Bits reserved for future specification.", HFILL }},
162     { &hf_trill_multi_dst,
163       { "Multi Destination", "trill.multi_dst",
164         FT_BOOLEAN, 16, TFS(&multi_dst_strings), TRILL_MULTI_DST_MASK,
165         "A boolean specifying if this is a multi-destination frame.", HFILL }},
166     { &hf_trill_op_len,
167       { "Option Length", "trill.op_len",
168         FT_UINT16, BASE_DEC_HEX, NULL, TRILL_OP_LEN_MASK,
169         "The length of the options field of this frame.", HFILL }},
170     { &hf_trill_hop_cnt,
171       { "Hop Count", "trill.hop_cnt",
172         FT_UINT16, BASE_DEC_HEX, NULL, TRILL_HOP_CNT_MASK,
173         "The remaining hop count for this frame.", HFILL }},
174     { &hf_trill_egress_nick,
175       { "Egress/Root RBridge Nickname", "trill.egress_nick",
176         FT_UINT16, BASE_DEC_HEX|BASE_RANGE_STRING, RVALS(nickname_strings), 0x0,
177         "The Egress or Distribution Tree Root RBridge Nickname.", HFILL }},
178     { &hf_trill_ingress_nick,
179       { "Ingress RBridge Nickname", "trill.ingress_nick",
180         FT_UINT16, BASE_DEC_HEX|BASE_RANGE_STRING, RVALS(nickname_strings), 0x0,
181         "The Ingress RBridge Nickname.", HFILL }},
182     { &hf_trill_options,
183       { "Options", "trill.options",
184         FT_BYTES, BASE_NONE, NULL, 0x0,
185         "The TRILL Options field.", HFILL }}
186   };
187
188   static gint *ett[] = {
189     &ett_trill
190   };
191
192   proto_trill = proto_register_protocol("TRILL", "TRILL", "trill");
193   proto_register_field_array(proto_trill, hf, array_length(hf));
194   proto_register_subtree_array(ett, array_length(ett));
195 }
196
197 void
198 proto_reg_handoff_trill(void)
199 {
200   dissector_handle_t trill_handle;
201
202   trill_handle = new_create_dissector_handle(dissect_trill, proto_trill);
203   dissector_add_uint("ethertype", ETHERTYPE_TRILL, trill_handle);
204
205   eth_dissector = find_dissector( "eth" ) ;
206 }
207