HTTPS (almost) everywhere.
[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  * SPDX-License-Identifier: GPL-2.0-or-later
12  */
13
14 #include "config.h"
15
16 #include <epan/packet.h>
17 #include <epan/etypes.h>
18 #include <epan/prefs.h>
19
20 #define    PRP_LAN_A                               10
21 #define    PRP_LAN_B                               11
22
23 static const value_string prp_lan_vals[] = {
24     {PRP_LAN_A, "LAN A"},
25     {PRP_LAN_B, "LAN B"},
26     {0, NULL}
27 };
28
29 /**********************************************************/
30 /* Initialize the protocol and registered fields      */
31 /**********************************************************/
32
33 void proto_register_prp(void);
34
35 static int proto_prp = -1;
36
37
38 /* Initialize trailer fields */
39 static int hf_prp_redundancy_control_trailer_sequence_nr = -1;
40 static int hf_prp_redundancy_control_trailer_lan = -1;
41 static int hf_prp_redundancy_control_trailer_size = -1;
42 static int hf_prp_redundancy_control_trailer_suffix = -1;
43 static int hf_prp_redundancy_control_trailer_version = -1;
44
45
46 /* Initialize the subtree pointers */
47 static gint ett_prp_redundancy_control_trailer = -1;
48
49
50 /* Code to actually dissect the packets */
51 static int
52 dissect_prp_redundancy_control_trailer(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void* data _U_)
53 {
54     proto_item *ti;
55     proto_tree *prp_tree;
56     guint       i;
57     guint       length;
58     guint       offset;
59     guint16     lan_id;
60     guint16     lsdu_size;
61     guint16     prp1_suffix;
62     guint       trailer_start;
63     guint       trailer_length;
64
65     trailer_start = 0;
66     trailer_length = 0;
67     length = tvb_reported_length(tvb);
68
69     if(length < 14)
70         return 0;
71
72     /*
73      * This is horribly broken.  It assumes the frame is an Ethernet
74      * frame, with a type field at an offset of 12 bytes from the header.
75      * That is not guaranteed to be true.
76      *
77      * Ideally, this should be a heuristic dissector registered in
78      * the "eth.trailer" heuristic dissector table (and it can
79      * be registered as "disabled by default" there); unfortunately,
80      * it needs to know the length of the entire frame for the
81      * PRP-0 heuristic, so it'd have to be passed that length
82      * out of band.
83      */
84     if (!tvb_bytes_exist(tvb, 12, 2))
85         return 0;
86     if(ETHERTYPE_VLAN == tvb_get_ntohs(tvb, 12)) /* tagged frame */
87     {
88         offset = 18;
89     }
90     else /* untagged */
91     {
92         offset = 14;
93     }
94
95     if (!tree)
96         return tvb_captured_length(tvb);
97
98     /*
99      * Is there enough data in the packet to every try to search for a
100      * trailer?
101      */
102     if (!tvb_bytes_exist(tvb, (length-4)+2, 2))
103         return 0;  /* no */
104
105     /* search for PRP-0 trailer */
106     /* If the frame is >  64 bytes, the PRP-0 trailer is always at the end. */
107     /* If the frame is <= 64 bytes, the PRP-0 trailer may be anywhere (before the padding) */
108     for(i=length-4; i>=offset; i--)
109     {
110         lan_id    = tvb_get_ntohs(tvb, (i+2)) >> 12;
111         lsdu_size = tvb_get_ntohs(tvb, (i+2)) & 0x0fff;
112         if(lsdu_size == i+4-offset && (lan_id == 0xa || lan_id == 0xb))
113         {
114             trailer_start  = i;
115             trailer_length = 4;
116             break;
117         }
118
119         if (length > 64) {
120             break; /* don't search, just check the last position */
121         }
122     }
123
124     /* check for PRP-1 trailer */
125     /* PRP-1 trailer is always at the end of the frame, after any padding. */
126     {
127         lan_id      = tvb_get_ntohs(tvb, length-4) >> 12;
128         lsdu_size   = tvb_get_ntohs(tvb, length-4) & 0x0fff;
129         prp1_suffix = tvb_get_ntohs(tvb, length-2);
130
131         if(prp1_suffix == ETHERTYPE_PRP && (lan_id == 0xa || lan_id == 0xb))
132         {
133             /* We don't check the lsdu_size, we just display whether
134                it's correct. Helpful for testing, because different
135                definitions of the lsdu_size did exist. */
136             trailer_start  = length-6;
137             trailer_length = 6;
138         }
139     }
140
141     if(trailer_length != 0)
142     {
143         /* create display subtree for the protocol */
144         ti = proto_tree_add_item(tree, proto_prp, tvb, trailer_start,
145                                  trailer_length, ENC_NA);
146
147         prp_tree = proto_item_add_subtree(ti, ett_prp_redundancy_control_trailer);
148
149         if (trailer_length == 4) {
150             ti = proto_tree_add_string(prp_tree, hf_prp_redundancy_control_trailer_version,
151                                        tvb, trailer_start, trailer_length, "PRP-0");
152         } else {
153             ti = proto_tree_add_string(prp_tree, hf_prp_redundancy_control_trailer_version,
154                                        tvb, trailer_start, trailer_length, "PRP-1");
155         }
156         proto_item_set_generated(ti);
157
158         proto_tree_add_item(prp_tree, hf_prp_redundancy_control_trailer_sequence_nr,
159                             tvb, trailer_start, 2, ENC_BIG_ENDIAN);
160
161         proto_tree_add_item(prp_tree, hf_prp_redundancy_control_trailer_lan,
162                             tvb, trailer_start+2, 2, ENC_BIG_ENDIAN);
163
164         if (trailer_length == 4) {
165             /* PRP-0 */
166             proto_tree_add_item(prp_tree, hf_prp_redundancy_control_trailer_size,
167                                 tvb, trailer_start+2, 2, ENC_BIG_ENDIAN);
168         } else {
169             /* PRP-1 */
170             int lsdu_size_correct = length-offset;
171             if (lsdu_size == lsdu_size_correct) {
172                 proto_tree_add_uint_format(prp_tree, hf_prp_redundancy_control_trailer_size,
173                                            tvb, trailer_start+2, 2, lsdu_size,
174                                            "LSDU size: %d [correct]", lsdu_size);
175             } else {
176                 proto_tree_add_uint_format(prp_tree, hf_prp_redundancy_control_trailer_size,
177                                            tvb, trailer_start+2, 2, lsdu_size,
178                                            "LSDU size: %d [WRONG, should be %d]", lsdu_size, lsdu_size_correct);
179             }
180             /* suffix */
181             proto_tree_add_item(prp_tree, hf_prp_redundancy_control_trailer_suffix,
182                                 tvb, trailer_start+4, 2, ENC_BIG_ENDIAN);
183         }
184     }
185     return tvb_captured_length(tvb);
186 }
187
188 /* Register the protocol with Wireshark */
189 void proto_register_prp(void)
190 {
191     static hf_register_info hf[] = {
192         /*trailer*/
193         { &hf_prp_redundancy_control_trailer_sequence_nr,
194             { "Sequence number", "prp.trailer.prp_sequence_nr",
195             FT_UINT16, BASE_DEC, NULL, 0x00,
196             NULL, HFILL }
197         },
198
199         { &hf_prp_redundancy_control_trailer_lan,
200             { "LAN", "prp.trailer.prp_lan",
201             FT_UINT16, BASE_DEC, VALS(prp_lan_vals), 0xf000,
202             NULL, HFILL }
203         },
204
205         { &hf_prp_redundancy_control_trailer_size,
206             { "Size", "prp.trailer.prp_size",
207             FT_UINT16, BASE_DEC, NULL, 0x0fff,
208             NULL, HFILL }
209         },
210
211         { &hf_prp_redundancy_control_trailer_suffix,
212             { "Suffix", "prp.trailer.prp1_suffix",
213             FT_UINT16, BASE_HEX, NULL, 0x00,
214             NULL, HFILL }
215         },
216
217         { &hf_prp_redundancy_control_trailer_version,
218             { "PRP Version", "prp.trailer.version",
219             FT_STRING, BASE_NONE, NULL, 0x00,
220             NULL, HFILL }
221         }
222     };
223
224     static gint *ett[] = {
225         &ett_prp_redundancy_control_trailer,
226     };
227
228     module_t *prp_module;
229     dissector_handle_t prp_handle;
230
231     /* Register the protocol name and description */
232     proto_prp = proto_register_protocol("Parallel Redundancy Protocol (IEC62439 Part 3)", "PRP", "prp");
233
234     /*  Post dissectors (such as the trailer dissector for this protocol)
235      *  get called for every single frame anyone loads into Wireshark.
236      *  Since this protocol is not of general interest we disable this
237      *  protocol by default.
238      */
239     proto_disable_by_default(proto_prp);
240
241     prp_module = prefs_register_protocol(proto_prp, NULL);
242
243     prefs_register_obsolete_preference(prp_module, "enable");
244
245     /* Required function calls to register the header fields and subtree used */
246     proto_register_field_array(proto_prp, hf, array_length(hf));
247     proto_register_subtree_array(ett, array_length(ett));
248
249     prp_handle = register_dissector("prp", dissect_prp_redundancy_control_trailer, proto_prp);
250
251     register_postdissector(prp_handle);
252 }
253
254 /*
255  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
256  *
257  * Local variables:
258  * c-basic-offset: 4
259  * tab-width: 8
260  * indent-tabs-mode: nil
261  * End:
262  *
263  * vi: set shiftwidth=4 tabstop=8 expandtab:
264  * :indentSize=4:tabSize=8:noTabs=true:
265  */