Fixup: tvb_get_string(z) -> tvb_get_string(z)_enc
[metze/wireshark/wip.git] / epan / dissectors / packet-prp.c
1 /* packet-prp.c
2  * Routines for PRP (Parallel Redundancy Protocol; IEC62439 Part 3) dissection
3  * Copyright 2007, Sven Meier <msv[AT]zhwin.ch>
4  * Copyright 2011, Martin Renold <reld[AT]zhaw.ch>
5  * Copyright 2011, Florian Reichert <refl [AT] zhaw.ch>
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald[AT]wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (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
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24  */
25
26 #include "config.h"
27
28 #include <glib.h>
29 #include <epan/packet.h>
30 #include <epan/etypes.h>
31 #include <epan/prefs.h>
32
33 #define    PRP_LAN_A                               10
34 #define    PRP_LAN_B                               11
35
36 static const value_string prp_lan_vals[] = {
37     {PRP_LAN_A, "LAN A"},
38     {PRP_LAN_B, "LAN B"},
39     {0, NULL}
40 };
41
42 /**********************************************************/
43 /* Initialize the protocol and registered fields      */
44 /**********************************************************/
45
46 void proto_register_prp(void);
47 void proto_reg_handoff_prp(void);
48
49 static int proto_prp = -1;
50
51
52 /* Initialize trailer fields */
53 static int hf_prp_redundancy_control_trailer_sequence_nr = -1;
54 static int hf_prp_redundancy_control_trailer_lan = -1;
55 static int hf_prp_redundancy_control_trailer_size = -1;
56 static int hf_prp_redundancy_control_trailer_suffix = -1;
57 static int hf_prp_redundancy_control_trailer_version = -1;
58
59
60 /* Initialize the subtree pointers */
61 static gint ett_prp_redundancy_control_trailer = -1;
62
63
64 /*  Post dissectors (such as the trailer dissector for this protocol)
65  *  get called for every single frame anyone loads into Wireshark.
66  *  Since this protocol is not of general interest we disable this
67  *  protocol by default.
68  *
69  *  This is done separately from the disabled protocols list mainly so
70  *  we can disable it by default.  XXX Maybe there's a better way.
71  */
72 static gboolean prp_enable_dissector = FALSE;
73
74
75 /* Code to actually dissect the packets */
76 static void
77 dissect_prp_redundancy_control_trailer(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
78 {
79     proto_item *ti;
80     proto_tree *prp_tree;
81     guint       i;
82     guint       length;
83     guint       offset;
84     guint16     lan_id;
85     guint16     lsdu_size;
86     guint16     prp1_suffix;
87     guint       trailer_start;
88     guint       trailer_length;
89
90     if (!tree)
91         return;
92
93     trailer_start = 0;
94     trailer_length = 0;
95     length = tvb_reported_length(tvb);
96
97     if(length < 14)
98     {
99         return;
100     }
101
102     if(ETHERTYPE_VLAN == tvb_get_ntohs(tvb, 12)) /* tagged frame */
103     {
104         offset = 18;
105     }
106     else /* untagged */
107     {
108         offset = 14;
109     }
110
111     /* search for PRP-0 trailer */
112     /* If the frame is >  64 bytes, the PRP-0 trailer is always at the end. */
113     /* If the frame is <= 64 bytes, the PRP-0 trailer may be anywhere (before the padding) */
114     for(i=length-4; i>=offset; i--)
115     {
116         lan_id    = tvb_get_ntohs(tvb, (i+2)) >> 12;
117         lsdu_size = tvb_get_ntohs(tvb, (i+2)) & 0x0fff;
118         if(lsdu_size == i+4-offset && (lan_id == 0xa || lan_id == 0xb))
119         {
120             trailer_start  = i;
121             trailer_length = 4;
122             break;
123         }
124
125         if (length > 64) {
126             break; /* don't search, just check the last position */
127         }
128     }
129
130     /* check for PRP-1 trailer */
131     /* PRP-1 trailer is always at the end of the frame, after any padding. */
132     {
133         lan_id      = tvb_get_ntohs(tvb, length-4) >> 12;
134         lsdu_size   = tvb_get_ntohs(tvb, length-4) & 0x0fff;
135         prp1_suffix = tvb_get_ntohs(tvb, length-2);
136
137         if(prp1_suffix == ETHERTYPE_PRP && (lan_id == 0xa || lan_id == 0xb))
138         {
139             /* We don't check the lsdu_size, we just display whether
140                it's correct. Helpful for testing, because different
141                definitions of the lsdu_size did exist. */
142             trailer_start  = length-6;
143             trailer_length = 6;
144         }
145     }
146
147     if(trailer_length != 0)
148     {
149         /* create display subtree for the protocol */
150         ti = proto_tree_add_item(tree, proto_prp, tvb, trailer_start,
151                                  trailer_length, ENC_NA);
152
153         prp_tree = proto_item_add_subtree(ti, ett_prp_redundancy_control_trailer);
154
155         if (trailer_length == 4) {
156             ti = proto_tree_add_string(prp_tree, hf_prp_redundancy_control_trailer_version,
157                                        tvb, trailer_start, trailer_length, "PRP-0");
158         } else {
159             ti = proto_tree_add_string(prp_tree, hf_prp_redundancy_control_trailer_version,
160                                        tvb, trailer_start, trailer_length, "PRP-1");
161         }
162         PROTO_ITEM_SET_GENERATED(ti);
163
164         proto_tree_add_item(prp_tree, hf_prp_redundancy_control_trailer_sequence_nr,
165                             tvb, trailer_start, 2, ENC_BIG_ENDIAN);
166
167         proto_tree_add_item(prp_tree, hf_prp_redundancy_control_trailer_lan,
168                             tvb, trailer_start+2, 2, ENC_BIG_ENDIAN);
169
170         if (trailer_length == 4) {
171             /* PRP-0 */
172             proto_tree_add_item(prp_tree, hf_prp_redundancy_control_trailer_size,
173                                 tvb, trailer_start+2, 2, ENC_BIG_ENDIAN);
174         } else {
175             /* PRP-1 */
176             int lsdu_size_correct = length-offset;
177             if (lsdu_size == lsdu_size_correct) {
178                 proto_tree_add_uint_format(prp_tree, hf_prp_redundancy_control_trailer_size,
179                                            tvb, trailer_start+2, 2, lsdu_size,
180                                            "LSDU size: %d [correct]", lsdu_size);
181             } else {
182                 proto_tree_add_uint_format(prp_tree, hf_prp_redundancy_control_trailer_size,
183                                            tvb, trailer_start+2, 2, lsdu_size,
184                                            "LSDU size: %d [WRONG, should be %d]", lsdu_size, lsdu_size_correct);
185             }
186             /* suffix */
187             proto_tree_add_item(prp_tree, hf_prp_redundancy_control_trailer_suffix,
188                                 tvb, trailer_start+4, 2, ENC_BIG_ENDIAN);
189         }
190     }
191 }
192
193 /* Register the protocol with Wireshark */
194 void proto_register_prp(void)
195 {
196     static hf_register_info hf[] = {
197         /*trailer*/
198         { &hf_prp_redundancy_control_trailer_sequence_nr,
199             { "Sequence number", "prp.trailer.prp_sequence_nr",
200             FT_UINT16, BASE_DEC, NULL, 0x00,
201             NULL, HFILL }
202         },
203
204         { &hf_prp_redundancy_control_trailer_lan,
205             { "LAN", "prp.trailer.prp_lan",
206             FT_UINT16, BASE_DEC, VALS(prp_lan_vals), 0xf000,
207             NULL, HFILL }
208         },
209
210         { &hf_prp_redundancy_control_trailer_size,
211             { "Size", "prp.trailer.prp_size",
212             FT_UINT16, BASE_DEC, NULL, 0x0fff,
213             NULL, HFILL }
214         },
215
216         { &hf_prp_redundancy_control_trailer_suffix,
217             { "Suffix", "prp.trailer.prp1_suffix",
218             FT_UINT16, BASE_HEX, NULL, 0x00,
219             NULL, HFILL }
220         },
221
222         { &hf_prp_redundancy_control_trailer_version,
223             { "PRP Version", "prp.trailer.version",
224             FT_STRING, BASE_NONE, NULL, 0x00,
225             NULL, HFILL }
226         }
227     };
228
229     static gint *ett[] = {
230         &ett_prp_redundancy_control_trailer,
231     };
232
233     module_t *prp_module;
234
235     /* Register the protocol name and description */
236     proto_prp = proto_register_protocol("Parallel Redundancy Protocol (IEC62439 Part 3)",
237                         "PRP", "prp");
238     prp_module = prefs_register_protocol(proto_prp, proto_reg_handoff_prp);
239
240     prefs_register_bool_preference(prp_module, "enable", "Enable dissector",
241                        "Enable this dissector (default is false)",
242                        &prp_enable_dissector);
243
244     /* Required function calls to register the header fields and subtree used */
245     proto_register_field_array(proto_prp, hf, array_length(hf));
246     proto_register_subtree_array(ett, array_length(ett));
247
248 }
249
250 void proto_reg_handoff_prp(void)
251 {
252     static gboolean prefs_initialized = FALSE;
253
254     if (!prefs_initialized) {
255         dissector_handle_t prp_redundancy_control_trailer_handle;
256
257         prp_redundancy_control_trailer_handle = create_dissector_handle(dissect_prp_redundancy_control_trailer, proto_prp);
258         register_postdissector(prp_redundancy_control_trailer_handle);
259
260         prefs_initialized = TRUE;
261     }
262
263     proto_set_decoding(proto_prp, prp_enable_dissector);
264 }