From Didier Gautheron:
[obnox/wireshark/wip.git] / epan / dissectors / packet-pw-eth.c
1 /* packet-pw-eth.c
2  * Routines for ethernet PW dissection: it should be conform to RFC 4448.
3  *
4  * Copyright 2008 _FF_
5  *
6  * Francesco Fondelli <francesco dot fondelli, gmail dot com>
7  *
8  * $Id$
9  *
10  * Wireshark - Network traffic analyzer
11  * By Gerald Combs <gerald@wireshark.org>
12  * Copyright 1998 Gerald Combs
13  *
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27  */
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <glib.h>
37 #include <epan/packet.h>
38 #include <epan/addr_resolv.h>
39
40 #include "packet-mpls.h"
41
42 static gint proto_pw_eth_cw = -1;
43 static gint proto_pw_eth_nocw = -1;
44 static gint proto_pw_eth_heuristic = -1;
45
46 static gint ett_pw_eth = -1;
47
48 static int hf_pw_eth = -1;
49 static int hf_pw_eth_cw = -1;
50 static int hf_pw_eth_cw_sequence_number = -1;
51
52 static dissector_handle_t eth_withoutfcs_handle;
53 static dissector_handle_t pw_eth_handle_cw;
54 static dissector_handle_t pw_eth_handle_nocw;
55
56 static void
57 dissect_pw_eth_cw(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
58 {
59         proto_tree *pw_eth_tree = NULL;
60         proto_item *ti = NULL;
61         tvbuff_t *next_tvb = NULL;
62         guint16 sequence_number = 0;
63         
64         if (tvb_reported_length_remaining(tvb, 0) < 4) {
65                 if (tree)
66                         proto_tree_add_text(tree, tvb, 0, -1, 
67                                             "Error processing Message");
68                 return;
69         }
70
71         if (dissect_try_cw_first_nibble(tvb, pinfo, tree)) 
72                 return;
73
74         sequence_number = tvb_get_ntohs(tvb, 2);
75         if (tree) {
76                 ti = proto_tree_add_boolean(tree, hf_pw_eth_cw, 
77                                             tvb, 0, 0, TRUE);
78                 PROTO_ITEM_SET_HIDDEN(ti);
79                 ti = proto_tree_add_item(tree, proto_pw_eth_cw, 
80                                          tvb, 0, 4, FALSE);
81                 pw_eth_tree = proto_item_add_subtree(ti, ett_pw_eth);
82                 if (pw_eth_tree == NULL)
83                         return;
84                 proto_tree_add_uint_format(pw_eth_tree, 
85                                            hf_pw_eth_cw_sequence_number,
86                                            tvb, 2, 2, sequence_number,
87                                            "Sequence Number: %d", 
88                                            sequence_number);
89         }
90         next_tvb = tvb_new_subset_remaining(tvb, 4);
91         {
92                 /*
93                  * When Ethernet frames being decoded, pinfo->ethertype is extracted 
94                  * from the top-level Ethernet frame. Dissection of Ethernet PW payload
95                  * overwrites this value as the same dissector is invoked again.
96                  * This may lead to undesired behavior (like disappearance of "Link"
97                  * tab from the "Decode as" menu).
98                  *
99                  * Let's save/restore ethertype. --ATA 
100                  *
101                  * XXX it looks that more pinfo members (or even the whole pinfo) 
102                  * XXX should be saved/restored in PW cases. Multilayer encapsulations, 
103                  * XXX like ethernet/mpls/ethernet-pw/ip/vlan, may lead to undesired 
104                  * XXX changes if pinfo->ipproto, ptype etc.
105                  */
106                 guint32 etype_save = pinfo->ethertype;
107                 call_dissector(eth_withoutfcs_handle, next_tvb, pinfo, tree);
108                 pinfo->ethertype = etype_save;
109         }
110 }
111
112 static void
113 dissect_pw_eth_nocw(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
114 {
115         tvbuff_t *next_tvb = NULL;
116         proto_item *ti = NULL;
117
118         if (tree) {
119                 ti = proto_tree_add_boolean(tree, hf_pw_eth, tvb, 0, 0, TRUE);
120                 PROTO_ITEM_SET_HIDDEN(ti);
121         }
122         next_tvb = tvb_new_subset_remaining(tvb, 0);
123         {
124                 guint32 etype_save = pinfo->ethertype;
125                 call_dissector(eth_withoutfcs_handle, next_tvb, pinfo, tree);
126                 pinfo->ethertype = etype_save;
127         }
128 }
129
130 /* 
131  * FF: this function returns TRUE if the first 12 bytes in tvb looks like
132  *     two valid ethernet addresses.  FALSE otherwise. 
133  */
134 static gboolean 
135 looks_like_plain_eth(tvbuff_t *tvb _U_)
136 {
137         const gchar *manuf_name_da = NULL;
138         const gchar *manuf_name_sa = NULL;
139
140         if (tvb_reported_length_remaining(tvb, 0) < 14) {
141                 return FALSE;
142         }
143
144         manuf_name_da = get_manuf_name_if_known(tvb_get_ptr(tvb, 0, 6));
145         manuf_name_sa = get_manuf_name_if_known(tvb_get_ptr(tvb, 6, 6));
146
147         if (manuf_name_da && manuf_name_sa) {
148                 return TRUE;
149         }
150
151         return FALSE;
152 }
153
154 static void 
155 dissect_pw_eth_heuristic(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
156 {
157         if (looks_like_plain_eth(tvb)) {
158                 call_dissector(pw_eth_handle_nocw, tvb, pinfo, tree);
159         } else {
160                 call_dissector(pw_eth_handle_cw, tvb, pinfo, tree);
161         }
162 }
163
164 void
165 proto_register_pw_eth(void)
166 {
167         static hf_register_info hf[] = {
168                 {
169                         &hf_pw_eth,
170                         {
171                                 "PW (ethernet)", 
172                                 "pweth", FT_BOOLEAN, 
173                                 BASE_NONE, NULL, 0x0, NULL, HFILL
174                         }
175                 },
176                 {
177                         &hf_pw_eth_cw,
178                         {
179                                 "PW Control Word (ethernet)", 
180                                 "pweth.cw", FT_BOOLEAN, 
181                                 BASE_NONE, NULL, 0x0, NULL, HFILL
182                         }
183                 },
184                 {
185                         &hf_pw_eth_cw_sequence_number,
186                         {
187                                 "PW sequence number (ethernet)", 
188                                 "pweth.cw.sequence_number", FT_UINT16, 
189                                 BASE_DEC, NULL, 0x0, NULL, HFILL
190                         }
191                 }
192         };
193
194         static gint *ett[] = {
195                 &ett_pw_eth
196         };
197
198         proto_pw_eth_cw = 
199           proto_register_protocol("PW Ethernet Control Word",
200                                   "Ethernet PW (with CW)",
201                                   "pwethcw");
202         proto_pw_eth_nocw = 
203           proto_register_protocol("Ethernet PW (no CW)", /* not displayed */
204                                   "Ethernet PW (no CW)",
205                                   "pwethnocw");
206         proto_pw_eth_heuristic = 
207           proto_register_protocol("Ethernet PW (CW heuristic)", /* not disp. */
208                                   "Ethernet PW (CW heuristic)", 
209                                   "pwethheuristic");
210         proto_register_field_array(proto_pw_eth_cw, hf, array_length(hf));
211         proto_register_subtree_array(ett, array_length(ett));   
212         register_dissector("pw_eth_cw", dissect_pw_eth_cw, proto_pw_eth_cw);
213         register_dissector("pw_eth_nocw", dissect_pw_eth_nocw, 
214                            proto_pw_eth_nocw);
215         register_dissector("pw_eth_heuristic", dissect_pw_eth_heuristic, 
216                            proto_pw_eth_heuristic);
217 }
218
219 void
220 proto_reg_handoff_pw_eth(void)
221 {
222         dissector_handle_t pw_eth_handle_heuristic;
223
224         eth_withoutfcs_handle = find_dissector("eth_withoutfcs");
225
226         pw_eth_handle_cw = find_dissector("pw_eth_cw");
227         dissector_add("mpls.label", LABEL_INVALID, pw_eth_handle_cw);
228
229         pw_eth_handle_nocw = find_dissector("pw_eth_nocw");
230         dissector_add("mpls.label", LABEL_INVALID, pw_eth_handle_nocw);
231
232         pw_eth_handle_heuristic = find_dissector("pw_eth_heuristic");
233         dissector_add("mpls.label", LABEL_INVALID, pw_eth_handle_heuristic);
234 }