1 /* packet-hsr-prp-supervision.c
2  * Routines for HSR/PRP supervision dissection (IEC62439 Part 3)
3  * Copyright 2009, Florian Reichert <refl[AT]zhaw.ch>
4  * Copyright 2011, Martin Renold <reld[AT]zhaw.ch>
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald[AT]wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * SPDX-License-Identifier: GPL-2.0-or-later
11  */
12 
13 #include "config.h"
14 
15 #include <epan/packet.h>
16 #include <epan/etypes.h>
17 
18 void proto_register_hsr_prp_supervision(void);
19 void proto_reg_handoff_hsr_prp_supervision(void);
20 
21 /**********************************************************/
22 /* Channel values for the supervision type field          */
23 /**********************************************************/
24 
25 static const value_string type_vals[] = {
26     {20, "PRP Node (Duplicate Discard)"},
27     {21, "PRP Node (Duplicate Accept)"},
28     {22, "Obsolete TLV value"},
29     {23, "HSR Node"},
30     {30, "Redundancy Box MAC Address"},
31     {31, "Virtual Dual Attached Node"},
32     {0,  "End of TLVs"},
33     {0,  NULL}
34 };
35 
36 /**********************************************************/
37 /* Initialize the protocol and registered fields          */
38 /**********************************************************/
39 
40 static int proto_hsr_prp_supervision = -1;
41 
42 /* Initialize supervision frame fields */
43 static int hf_hsr_prp_supervision_path = -1;
44 static int hf_hsr_prp_supervision_version = -1;
45 static int hf_hsr_prp_supervision_seqno = -1;
46 static int hf_hsr_prp_supervision_tlv_type = -1;
47 static int hf_hsr_prp_supervision_tlv_length = -1;
48 static int hf_hsr_prp_supervision_source_mac_address_A = -1;
49 static int hf_hsr_prp_supervision_source_mac_address_B = -1;
50 static int hf_hsr_prp_supervision_source_mac_address = -1;
51 static int hf_hsr_prp_supervision_red_box_mac_address = -1;
52 static int hf_hsr_prp_supervision_vdan_mac_address = -1;
53 
54 /* Initialize the subtree pointers */
55 static gint ett_hsr_prp_supervision = -1;
56 
57 /* Code to actually dissect the packets */
58 static int
dissect_hsr_prp_supervision(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)59 dissect_hsr_prp_supervision(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
60 {
61     proto_item *ti;
62     proto_tree *hsr_prp_supervision_tree;
63     guint8 tlv_type;
64     guint8 tlv_length;
65     guint16 sup_version;
66     int offset;
67 
68     col_set_str(pinfo->cinfo, COL_PROTOCOL, "HSR/PRP");
69 
70     /* may get modified later while parsing */
71     col_set_str(pinfo->cinfo, COL_INFO, "HSR or PRP Supervision");
72 
73     /* create display subtree for the protocol */
74     ti = proto_tree_add_item(tree, proto_hsr_prp_supervision, tvb, 0, -1, ENC_NA);
75 
76     hsr_prp_supervision_tree = proto_item_add_subtree(ti, ett_hsr_prp_supervision);
77 
78     offset = 0;
79 
80     /* SupVersion */
81     proto_tree_add_item(hsr_prp_supervision_tree, hf_hsr_prp_supervision_path,
82                         tvb, offset, 2, ENC_BIG_ENDIAN);
83     proto_tree_add_item(hsr_prp_supervision_tree, hf_hsr_prp_supervision_version,
84                         tvb, offset, 2, ENC_BIG_ENDIAN);
85     sup_version = tvb_get_ntohs(tvb, 0) & 0x0fff;
86     offset += 2;
87 
88     if (sup_version > 0) {
89         /* SupSequenceNumber */
90         proto_tree_add_item(hsr_prp_supervision_tree, hf_hsr_prp_supervision_seqno,
91                             tvb, offset, 2, ENC_BIG_ENDIAN);
92         offset += 2;
93     }
94 
95     while (tvb_reported_length_remaining(tvb, offset) > 0) {
96         /* TLV.type */
97         tlv_type = tvb_get_guint8(tvb, offset);
98         proto_tree_add_item(hsr_prp_supervision_tree, hf_hsr_prp_supervision_tlv_type,
99                             tvb, offset, 1, ENC_BIG_ENDIAN);
100         offset += 1;
101 
102         /* TLV.length */
103         tlv_length = tvb_get_guint8(tvb, offset);
104         proto_tree_add_item(hsr_prp_supervision_tree, hf_hsr_prp_supervision_tlv_length,
105                             tvb, offset, 1, ENC_BIG_ENDIAN);
106         offset += 1;
107 
108         /* TLV.value */
109         if ((tlv_type == 20 || tlv_type == 21 || tlv_type == 23) && (tlv_length == 6 || tlv_length == 12)) {
110             if (tlv_type == 23) {
111                 col_set_str(pinfo->cinfo, COL_INFO, "HSR Supervision");
112             } else {
113                 col_set_str(pinfo->cinfo, COL_INFO, "PRP Supervision");
114             }
115             if (tlv_length == 12) {
116                 /* MacAddressA, MacAddressB (PRP only) */
117                 proto_tree_add_item(hsr_prp_supervision_tree, hf_hsr_prp_supervision_source_mac_address_A,
118                                     tvb, offset, 6, ENC_NA);
119                 proto_tree_add_item(hsr_prp_supervision_tree, hf_hsr_prp_supervision_source_mac_address_B,
120                                     tvb, offset+6, 6, ENC_NA);
121                 /* PRP-0 supervision: if the node is not a RedBox, we have
122                    just read the last TLV. The next two octets are
123                    required to be zero by PRP-0. We will dissect those as
124                    "end of list" and break. */
125             } else {
126                 /* MacAddress */
127                 proto_tree_add_item(hsr_prp_supervision_tree, hf_hsr_prp_supervision_source_mac_address,
128                                     tvb, offset, 6, ENC_NA);
129             }
130         } else if (tlv_type == 30 && tlv_length == 6) {
131             /* RedBoxMacAddress */
132             proto_tree_add_item(hsr_prp_supervision_tree, hf_hsr_prp_supervision_red_box_mac_address,
133                                 tvb, offset, 6, ENC_NA);
134             if (sup_version == 0) {
135                 /* PRP-0 supervision: end of TLV data. Stop now, don't
136                    interpret the padding. */
137                 offset += tlv_length;
138                 break;
139             }
140         } else if (tlv_type == 31 && tlv_length == 6) {
141             /* VdanMacAddress */
142             proto_tree_add_item(hsr_prp_supervision_tree, hf_hsr_prp_supervision_vdan_mac_address,
143                                 tvb, offset, 6, ENC_NA);
144             if (sup_version == 0) {
145                 /* PRP-0 supervision: end of TLV data, padding starts */
146                 offset += tlv_length;
147                 break;
148             }
149         } else if (tlv_type == 0) {
150             /* End of TLV list. */
151             offset += tlv_length;
152             break;
153         } else {
154             /* unknown TLV.type, or unexpected TLV.length */
155         }
156         offset += tlv_length;
157     }
158 
159     proto_item_set_len(ti, offset);
160     /* Adjust the length of this tvbuff to include only the supervision data.
161        This allows the rest to be marked as padding. */
162     tvb_set_reported_length(tvb, offset);
163     return tvb_captured_length(tvb);
164 }
165 
166 
167 /* Register the protocol with Wireshark */
proto_register_hsr_prp_supervision(void)168 void proto_register_hsr_prp_supervision(void)
169 {
170 
171     static hf_register_info hf[] = {
172 
173         { &hf_hsr_prp_supervision_path,
174             { "Path", "hsr_prp_supervision.path",
175             FT_UINT16, BASE_DEC, NULL, 0xf000,
176             NULL, HFILL }
177         },
178         { &hf_hsr_prp_supervision_version,
179             { "Version", "hsr_prp_supervision.version",
180             FT_UINT16, BASE_DEC, NULL, 0x0fff,
181             NULL, HFILL }
182         },
183         { &hf_hsr_prp_supervision_seqno,
184             { "Sequence number", "hsr_prp_supervision.supervision_seqno",
185             FT_UINT16, BASE_DEC, NULL, 0x00,
186             NULL, HFILL }
187         },
188         { &hf_hsr_prp_supervision_tlv_type,
189             { "TLV type", "hsr_prp_supervision.tlv.type",
190             FT_UINT8, BASE_DEC, VALS(type_vals), 0x00,
191             NULL, HFILL }
192         },
193         { &hf_hsr_prp_supervision_tlv_length,
194             { "TLV length", "hsr_prp_supervision.tlv.length",
195             FT_UINT8, BASE_DEC, NULL, 0x00,
196             NULL, HFILL }
197         },
198         { &hf_hsr_prp_supervision_source_mac_address_A,
199             { "Source MAC Address A", "hsr_prp_supervision.source_mac_address_A",
200             FT_ETHER, BASE_NONE, NULL, 0x00,
201             NULL, HFILL }
202         },
203         { &hf_hsr_prp_supervision_source_mac_address_B,
204             { "Source MAC Address B", "hsr_prp_supervision.source_mac_address_B",
205             FT_ETHER, BASE_NONE, NULL, 0x00,
206             NULL, HFILL }
207         },
208         { &hf_hsr_prp_supervision_source_mac_address,
209             { "Source MAC Address", "hsr_prp_supervision.source_mac_address",
210             FT_ETHER, BASE_NONE, NULL, 0x00,
211             NULL, HFILL }
212         },
213         { &hf_hsr_prp_supervision_red_box_mac_address,
214             { "RedBox MAC Address", "hsr_prp_supervision.red_box_mac_address",
215             FT_ETHER, BASE_NONE, NULL, 0x00,
216             NULL, HFILL }
217         },
218         { &hf_hsr_prp_supervision_vdan_mac_address,
219             { "VDAN MAC Address", "hsr_prp_supervision.vdan_mac_address",
220             FT_ETHER, BASE_NONE, NULL, 0x00,
221             NULL, HFILL }
222         }
223     };
224 
225 
226     static gint *ett[] = {
227         &ett_hsr_prp_supervision
228     };
229 
230     /* Register the protocol name and description */
231     proto_hsr_prp_supervision = proto_register_protocol("HSR/PRP Supervision (IEC62439 Part 3)",
232                         "HSR_PRP_SUPERVISION", "hsr_prp_supervision");
233 
234 
235     /* Required function calls to register the header fields and subtree used */
236     proto_register_field_array(proto_hsr_prp_supervision, hf, array_length(hf));
237     proto_register_subtree_array(ett, array_length(ett));
238 }
239 
240 
proto_reg_handoff_hsr_prp_supervision(void)241 void proto_reg_handoff_hsr_prp_supervision(void)
242 {
243     dissector_handle_t hsr_prp_supervision_handle;
244     hsr_prp_supervision_handle = create_dissector_handle(dissect_hsr_prp_supervision, proto_hsr_prp_supervision);
245     dissector_add_uint("ethertype", ETHERTYPE_PRP, hsr_prp_supervision_handle);
246 }
247 
248 /*
249  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
250  *
251  * Local variables:
252  * c-basic-offset: 4
253  * tab-width: 8
254  * indent-tabs-mode: nil
255  * End:
256  *
257  * vi: set shiftwidth=4 tabstop=8 expandtab:
258  * :indentSize=4:tabSize=8:noTabs=true:
259  */
260