From Kovarththanan Rajaratnam via bug 3548:
[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
54 static void
55 dissect_pw_eth_cw(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
56 {
57         proto_tree *pw_eth_tree = NULL;
58         proto_item *ti = NULL;
59         tvbuff_t *next_tvb = NULL;
60         guint16 sequence_number = 0;
61         
62         if (tvb_reported_length_remaining(tvb, 0) < 4) {
63                 if (tree)
64                         proto_tree_add_text(tree, tvb, 0, -1, 
65                                             "Error processing Message");
66                 return;
67         }
68
69         if (dissect_try_cw_first_nibble(tvb, pinfo, tree)) 
70                 return;
71
72         sequence_number = tvb_get_ntohs(tvb, 2);
73         if (tree) {
74                 ti = proto_tree_add_boolean(tree, hf_pw_eth_cw, 
75                                             tvb, 0, 0, TRUE);
76                 PROTO_ITEM_SET_HIDDEN(ti);
77                 ti = proto_tree_add_item(tree, proto_pw_eth_cw, 
78                                          tvb, 0, 4, FALSE);
79                 pw_eth_tree = proto_item_add_subtree(ti, ett_pw_eth);
80                 if (pw_eth_tree == NULL)
81                         return;
82                 proto_tree_add_uint_format(pw_eth_tree, 
83                                            hf_pw_eth_cw_sequence_number,
84                                            tvb, 2, 2, sequence_number,
85                                            "Sequence Number: %d", 
86                                            sequence_number);
87         }
88         next_tvb = tvb_new_subset(tvb, 4, -1, -1);
89         call_dissector(eth_withoutfcs_handle, next_tvb, pinfo, tree);
90 }
91
92 static void
93 dissect_pw_eth_nocw(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
94 {
95         tvbuff_t *next_tvb = NULL;
96         proto_item *ti = NULL;
97
98         if (tree) {
99                 ti = proto_tree_add_boolean(tree, hf_pw_eth, tvb, 0, 0, TRUE);
100                 PROTO_ITEM_SET_HIDDEN(ti);
101         }
102         next_tvb = tvb_new_subset(tvb, 0, -1, -1);
103         call_dissector(eth_withoutfcs_handle, next_tvb, pinfo, tree);
104 }
105
106 /* 
107  * FF: this function returns TRUE if the first 12 bytes in tvb looks like
108  *     two valid ethernet addresses.  FALSE otherwise. 
109  */
110 static gboolean 
111 looks_like_plain_eth(tvbuff_t *tvb _U_)
112 {
113         const gchar *manuf_name_da = NULL;
114         const gchar *manuf_name_sa = NULL;
115
116         if (tvb_reported_length_remaining(tvb, 0) < 14) {
117                 return FALSE;
118         }
119
120         manuf_name_da = get_manuf_name_if_known(tvb_get_ptr(tvb, 0, 6));
121         manuf_name_sa = get_manuf_name_if_known(tvb_get_ptr(tvb, 6, 6));
122
123         if (manuf_name_da && manuf_name_sa) {
124                 return TRUE;
125         }
126
127         return FALSE;
128 }
129
130 static void 
131 dissect_pw_eth_heuristic(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
132 {
133         if (looks_like_plain_eth(tvb)) {
134                 call_dissector(find_dissector("pw_eth_nocw"), tvb, pinfo, tree);
135         } else {
136                 call_dissector(find_dissector("pw_eth_cw"), tvb, pinfo, tree);
137         }
138 }
139
140 void
141 proto_register_pw_eth(void)
142 {
143         static hf_register_info hf[] = {
144                 {
145                         &hf_pw_eth,
146                         {
147                                 "PW (ethernet)", 
148                                 "pweth", FT_BOOLEAN, 
149                                 BASE_NONE, NULL, 0x0, NULL, HFILL
150                         }
151                 },
152                 {
153                         &hf_pw_eth_cw,
154                         {
155                                 "PW Control Word (ethernet)", 
156                                 "pweth.cw", FT_BOOLEAN, 
157                                 BASE_NONE, NULL, 0x0, NULL, HFILL
158                         }
159                 },
160                 {
161                         &hf_pw_eth_cw_sequence_number,
162                         {
163                                 "PW sequence number (ethernet)", 
164                                 "pweth.cw.sequence_number", FT_UINT16, 
165                                 BASE_DEC, NULL, 0x0, NULL, HFILL
166                         }
167                 }
168         };
169
170         static gint *ett[] = {
171                 &ett_pw_eth
172         };
173
174         proto_pw_eth_cw = 
175           proto_register_protocol("PW Ethernet Control Word",
176                                   "Ethernet PW (with CW)",
177                                   "pwethcw");
178         proto_pw_eth_nocw = 
179           proto_register_protocol("Ethernet PW (no CW)", /* not displayed */
180                                   "Ethernet PW (no CW)",
181                                   "pwethnocw");
182         proto_pw_eth_heuristic = 
183           proto_register_protocol("Ethernet PW (CW heuristic)", /* not disp. */
184                                   "Ethernet PW (CW heuristic)", 
185                                   "pwethheuristic");
186         proto_register_field_array(proto_pw_eth_cw, hf, array_length(hf));
187         proto_register_subtree_array(ett, array_length(ett));   
188         register_dissector("pw_eth_cw", dissect_pw_eth_cw, proto_pw_eth_cw);
189         register_dissector("pw_eth_nocw", dissect_pw_eth_nocw, 
190                            proto_pw_eth_nocw);
191         register_dissector("pw_eth_heuristic", dissect_pw_eth_heuristic, 
192                            proto_pw_eth_heuristic);
193 }
194
195 void
196 proto_reg_handoff_pw_eth(void)
197 {
198         dissector_handle_t pw_eth_handle_cw;
199         dissector_handle_t pw_eth_handle_nocw;
200         dissector_handle_t pw_eth_handle_heuristic;
201
202         eth_withoutfcs_handle = find_dissector("eth_withoutfcs");
203
204         pw_eth_handle_cw = find_dissector("pw_eth_cw");
205         dissector_add("mpls.label", LABEL_INVALID, pw_eth_handle_cw);
206
207         pw_eth_handle_nocw = find_dissector("pw_eth_nocw");
208         dissector_add("mpls.label", LABEL_INVALID, pw_eth_handle_nocw);
209
210         pw_eth_handle_heuristic = find_dissector("pw_eth_heuristic");
211         dissector_add("mpls.label", LABEL_INVALID, pw_eth_handle_heuristic);
212 }