From ToddS via https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=5300 :
[obnox/wireshark/wip.git] / plugins / profinet / packet-pn-mrp.c
1 /* packet-pn-mrp.c
2  * Routines for PN-MRP (PROFINET Media Redundancy Protocol) 
3  * packet dissection.
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30
31 #ifdef HAVE_SYS_TYPES_H
32 #include <sys/types.h>
33 #endif
34
35 #include <glib.h>
36 #include <epan/packet.h>
37 #include <epan/dissectors/packet-dcerpc.h>
38 #include <epan/oui.h>
39 #include <epan/etypes.h>
40
41 #include "packet-pn.h"
42
43
44 static int proto_pn_mrp = -1;
45
46 static int hf_pn_mrp_type = -1;
47 static int hf_pn_mrp_length = -1;
48 static int hf_pn_mrp_version = -1;
49 static int hf_pn_mrp_sequence_id = -1;
50 static int hf_pn_mrp_sa = -1;
51 static int hf_pn_mrp_prio = -1;
52 static int hf_pn_mrp_port_role = -1;
53 static int hf_pn_mrp_ring_state = -1;
54 static int hf_pn_mrp_interval = -1;
55 static int hf_pn_mrp_transition = -1;
56 static int hf_pn_mrp_time_stamp = -1;
57 static int hf_pn_mrp_blocked = -1;
58 static int hf_pn_mrp_manufacturer_oui = -1;
59 static int hf_pn_mrp_domain_uuid = -1;
60 static int hf_pn_mrp_oui = -1;
61
62
63 static gint ett_pn_mrp = -1;
64
65
66
67 static const value_string pn_mrp_block_type_vals[] = {
68         { 0x00, "End" },
69         { 0x01, "Common" },
70         { 0x02, "Test" },
71         { 0x03, "TopologyChange" },
72         { 0x04, "LinkDown" },
73         { 0x05, "LinkUp" },
74     /*0x06 - 0x7E Reserved */
75         { 0x7F, "Organizationally Specific"},
76         { 0, NULL },
77 };
78
79 static const value_string pn_mrp_oui_vals[] = {
80         { OUI_PROFINET,         "PROFINET" },
81         { OUI_SIEMENS,          "SIEMENS" },
82
83         { 0, NULL }
84 };
85
86
87
88 static const value_string pn_mrp_port_role_vals[] = {
89         { 0x0000, "Primary ring port" },
90         { 0x0001, "Secondary ring port"},
91     /*0x0002 - 0xFFFF Reserved */
92
93     { 0, NULL }
94 };
95
96 static const value_string pn_mrp_ring_state_vals[] = {
97         { 0x0000, "Ring open" },
98         { 0x0001, "Ring closed"},
99     /*0x0002 - 0xFFFF Reserved */
100
101     { 0, NULL }
102 };
103
104
105 static const value_string pn_mrp_prio_vals[] = {
106         { 0x8000, "Default priority for redundancy manager" },
107
108     { 0, NULL }
109 };
110
111
112
113 static int
114 dissect_PNMRP_Common(tvbuff_t *tvb, int offset, 
115         packet_info *pinfo, proto_tree *tree, proto_item *item)
116 {
117     guint16 sequence_id;
118     e_uuid_t uuid;
119
120
121     /* MRP_SequenceID */
122     offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_mrp_sequence_id, &sequence_id);
123
124     /* MRP_DomainUUID */
125     offset = dissect_pn_uuid(tvb, offset, pinfo, tree, hf_pn_mrp_domain_uuid, &uuid);
126
127     col_append_str(pinfo->cinfo, COL_INFO, "Common");
128
129     proto_item_append_text(item, "Common");
130
131     return offset;
132 }
133
134
135 static int
136 dissect_PNMRP_LinkUp(tvbuff_t *tvb, int offset, 
137         packet_info *pinfo, proto_tree *tree, proto_item *item)
138 {
139     guint8 mac[6];
140     guint16 port_role;
141     guint16 interval;
142     guint16 blocked;
143
144     /* MRP_SA */
145     offset = dissect_pn_mac(tvb, offset, pinfo, tree, hf_pn_mrp_sa, mac);
146
147     /* MRP_PortRole */
148     offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_mrp_port_role, &port_role);
149
150     /* MRP_Interval */
151     offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_mrp_interval, &interval);
152
153     /* MRP_Blocked */
154     offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_mrp_blocked, &blocked);
155
156     /* Padding */
157     offset = dissect_pn_align4(tvb, offset, pinfo, tree);
158
159     col_append_str(pinfo->cinfo, COL_INFO, "LinkUp");
160
161     proto_item_append_text(item, "LinkUp");
162
163     return offset;
164 }
165
166
167 static int
168 dissect_PNMRP_LinkDown(tvbuff_t *tvb, int offset, 
169         packet_info *pinfo, proto_tree *tree, proto_item *item)
170 {
171     guint8 mac[6];
172     guint16 port_role;
173     guint16 interval;
174     guint16 blocked;
175
176     /* MRP_SA */
177     offset = dissect_pn_mac(tvb, offset, pinfo, tree, hf_pn_mrp_sa, mac);
178
179     /* MRP_PortRole */
180     offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_mrp_port_role, &port_role);
181
182     /* MRP_Interval */
183     offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_mrp_interval, &interval);
184
185     /* MRP_Blocked */
186     offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_mrp_blocked, &blocked);
187
188     /* Padding */
189     offset = dissect_pn_align4(tvb, offset, pinfo, tree);
190
191     col_append_str(pinfo->cinfo, COL_INFO, "LinkDown");
192
193     proto_item_append_text(item, "LinkDown");
194
195     return offset;
196 }
197
198
199 static int
200 dissect_PNMRP_Test(tvbuff_t *tvb, int offset, 
201         packet_info *pinfo, proto_tree *tree, proto_item *item)
202 {
203     guint16 prio;
204     guint8 mac[6];
205     guint16 port_role;
206     guint16 ring_state;
207     guint16 transition;
208     guint16 time_stamp;
209
210
211     /* MRP_Prio */
212     offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_mrp_prio, &prio);
213
214     /* MRP_SA */
215     offset = dissect_pn_mac(tvb, offset, pinfo, tree, hf_pn_mrp_sa, mac);
216
217     /* MRP_PortRole */
218     offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_mrp_port_role, &port_role);
219
220     /* MRP_RingState */
221     offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_mrp_ring_state, &ring_state);
222
223     /* MRP_Transition */
224     offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_mrp_transition, &transition);
225
226     /* MRP_TimeStamp */
227     offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_mrp_time_stamp, &time_stamp);
228
229     /* Padding */
230     offset = dissect_pn_align4(tvb, offset, pinfo, tree);
231
232     col_append_str(pinfo->cinfo, COL_INFO, "Test");
233
234     proto_item_append_text(item, "Test");
235
236     return offset;
237 }
238
239
240 static int
241 dissect_PNMRP_TopologyChange(tvbuff_t *tvb, int offset, 
242         packet_info *pinfo, proto_tree *tree, proto_item *item)
243 {
244     guint16 prio;
245     guint8 mac[6];
246     guint16 interval;
247
248
249     /* MRP_Prio */
250     offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_mrp_prio, &prio);
251
252     /* MRP_SA */
253     offset = dissect_pn_mac(tvb, offset, pinfo, tree, hf_pn_mrp_sa, mac);
254
255     /* MRP_Interval */
256     offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_mrp_interval, &interval);
257
258     /* Padding */
259     /*offset = dissect_pn_align4(tvb, offset, pinfo, tree);*/
260
261     col_append_str(pinfo->cinfo, COL_INFO, "TopologyChange");
262
263     proto_item_append_text(item, "TopologyChange");
264
265     return offset;
266 }
267
268
269 static int
270 dissect_PNMRP_Option(tvbuff_t *tvb, int offset, 
271         packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 length)
272 {
273     guint32 oui;
274
275
276     /* OUI (organizational unique id) */
277     offset = dissect_pn_oid(tvb, offset, pinfo,tree, hf_pn_mrp_oui, &oui);
278     length -= 3;
279         
280     switch (oui)
281         {
282         case OUI_SIEMENS:
283         proto_item_append_text(item, "Option(SIEMENS)");
284         /* Padding */
285         if (offset % 4) {
286             length -= 4 - (offset % 4);
287             offset = dissect_pn_align4(tvb, offset, pinfo, tree);
288         }
289         if(length != 0) {
290             offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, length);
291         }
292         col_append_str(pinfo->cinfo, COL_INFO, "Option(Siemens)");
293                 break;
294         default:
295         proto_item_append_text(item, "Option(Unknown-OUI)");
296         offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, length);
297
298         col_append_str(pinfo->cinfo, COL_INFO, "Option");
299     }
300
301     offset += length;
302
303     /* Padding */
304     offset = dissect_pn_align4(tvb, offset, pinfo, tree);
305
306     return offset;
307 }
308
309
310 static int
311 dissect_PNMRP_PDU(tvbuff_t *tvb, int offset, 
312         packet_info *pinfo, proto_tree *tree, proto_item *item)
313 {
314     guint16 version;
315     guint8 type;
316     guint8 length;
317     gint i;
318     tvbuff_t *new_tvb;
319
320
321     /* MRP_Version */
322     offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_mrp_version, &version);
323
324     /* the rest of the packet has 4byte alignment regarding to the beginning of the next TLV block! */
325     /* XXX - do we have to free this new tvb below? */
326     new_tvb = tvb_new_subset_remaining(tvb, offset);
327     offset = 0;
328
329     for(i=0; tvb_length_remaining(tvb, offset) > 0; i++) {
330         /* MRP_TLVHeader.Type */
331         offset = dissect_pn_uint8(new_tvb, offset, pinfo, tree, hf_pn_mrp_type, &type);
332
333         /* MRP_TLVHeader.Length */
334         offset = dissect_pn_uint8(new_tvb, offset, pinfo, tree, hf_pn_mrp_length, &length);
335
336         if(i != 0) {
337             col_append_str(pinfo->cinfo, COL_INFO, ", ");
338
339             proto_item_append_text(item, ", ");
340         }
341
342         switch(type) {
343         case(0x00):
344             /* no content */
345             col_append_str(pinfo->cinfo, COL_INFO, "End");
346             proto_item_append_text(item, "End");
347             return offset;
348             break;
349         case(0x01):
350             offset = dissect_PNMRP_Common(new_tvb, offset, pinfo, tree, item);
351             break;
352         case(0x02):
353             offset = dissect_PNMRP_Test(new_tvb, offset, pinfo, tree, item);
354             break;
355         case(0x03):
356             offset = dissect_PNMRP_TopologyChange(new_tvb, offset, pinfo, tree, item);
357             break;
358         case(0x04):
359             offset = dissect_PNMRP_LinkDown(new_tvb, offset, pinfo, tree, item);
360             break;
361         case(0x05):
362             offset = dissect_PNMRP_LinkUp(new_tvb, offset, pinfo, tree, item);
363             break;
364         case(0x7f):
365             offset = dissect_PNMRP_Option(new_tvb, offset, pinfo, tree, item, length);
366             break;
367         default:
368             offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, length);
369
370                 col_append_fstr(pinfo->cinfo, COL_INFO, "Unknown TLVType 0x%x", type);
371             proto_item_append_text(item, "Unknown TLVType 0x%x", type);
372         }
373     }
374
375     return offset;
376 }
377
378
379 /* Dissect MRP packets */
380 static void
381 dissect_PNMRP(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
382 {
383     proto_item *ti = NULL;
384     proto_tree *mrp_tree = NULL;
385         
386     guint32 offset = 0;
387
388     col_set_str(pinfo->cinfo, COL_PROTOCOL, "PN-MRP");
389                 
390     /* Clear the information column on summary display */
391     col_clear(pinfo->cinfo, COL_INFO);
392
393     if (tree) 
394     {
395         ti = proto_tree_add_item(tree, proto_pn_mrp, tvb, offset, -1, FALSE);
396         mrp_tree = proto_item_add_subtree(ti, ett_pn_mrp);
397     }
398
399     dissect_PNMRP_PDU(tvb, offset, pinfo, mrp_tree, ti);
400 }       
401
402
403 void
404 proto_register_pn_mrp (void)
405 {
406         static hf_register_info hf[] = {
407         { &hf_pn_mrp_type,
408                 { "Type", "pn_mrp.type", FT_UINT8, BASE_HEX, VALS(pn_mrp_block_type_vals), 0x0, NULL, HFILL }},
409         { &hf_pn_mrp_length,
410                 { "Length", "pn_mrp.length", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
411         { &hf_pn_mrp_version,
412                 { "Version", "pn_mrp.version", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
413         { &hf_pn_mrp_sequence_id,
414                 { "SequenceID", "pn_mrp.sequence_id", FT_UINT16, BASE_HEX, NULL, 0x0, "Unique sequence number to each outstanding service request", HFILL }},
415         { &hf_pn_mrp_sa,
416         { "SA", "pn_mrp.sa", FT_ETHER, BASE_NONE, 0x0, 0x0, NULL, HFILL }},
417         { &hf_pn_mrp_prio,
418                 { "Prio", "pn_mrp.prio", FT_UINT16, BASE_HEX, VALS(pn_mrp_prio_vals), 0x0, NULL, HFILL }},
419         { &hf_pn_mrp_port_role,
420                 { "PortRole", "pn_mrp.port_role", FT_UINT16, BASE_HEX, VALS(pn_mrp_port_role_vals), 0x0, NULL, HFILL }},
421         { &hf_pn_mrp_ring_state,
422                 { "RingState", "pn_mrp.ring_state", FT_UINT16, BASE_HEX, VALS(pn_mrp_ring_state_vals), 0x0, NULL, HFILL }},
423         { &hf_pn_mrp_interval,
424                 { "Interval", "pn_mrp.interval", FT_UINT16, BASE_DEC, NULL, 0x0, "Interval for next topologie change event (in ms)", HFILL }},
425         { &hf_pn_mrp_transition,
426                 { "Transition", "pn_mrp.transition", FT_UINT16, BASE_HEX, NULL, 0x0, "Number of transitions between media redundancy lost and ok states", HFILL }},
427         { &hf_pn_mrp_time_stamp,
428                 { "TimeStamp", "pn_mrp.time_stamp", FT_UINT16, BASE_HEX, NULL, 0x0, "Actual counter value of 1ms counter", HFILL }},
429         { &hf_pn_mrp_blocked,
430                 { "Blocked", "pn_mrp.blocked", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
431         { &hf_pn_mrp_manufacturer_oui,
432                 { "ManufacturerOUI", "pn_mrp.manufacturer_oui", FT_UINT24, BASE_HEX, VALS(pn_mrp_oui_vals), 0x0, NULL, HFILL }},
433         { &hf_pn_mrp_domain_uuid,
434                 { "DomainUUID", "pn_mrp.domain_uuid", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
435         { &hf_pn_mrp_oui,
436                 { "Organizationally Unique Identifier", "pn_mrp.oui", FT_UINT24, BASE_HEX,
437                 VALS(pn_mrp_oui_vals), 0x0, NULL, HFILL }},
438     };
439
440         static gint *ett[] = {
441                 &ett_pn_mrp
442     };
443
444     proto_pn_mrp = proto_register_protocol ("PROFINET MRP", "PN-MRP", "pn_mrp");
445         proto_register_field_array (proto_pn_mrp, hf, array_length (hf));
446         proto_register_subtree_array (ett, array_length (ett));
447 }
448
449
450 void
451 proto_reg_handoff_pn_mrp (void)
452 {
453         dissector_handle_t mrp_handle;
454
455
456         mrp_handle = create_dissector_handle(dissect_PNMRP,proto_pn_mrp);
457         dissector_add("ethertype", ETHERTYPE_MRP, mrp_handle);
458
459 }