nexmon – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /* packet-pn-ptcp.c
2 * Routines for PN-PTCP (PROFINET Precision Time Clock Protocol)
3 * packet dissection.
4 *
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 */
23  
24 #include "config.h"
25  
26 #include <epan/packet.h>
27 #include <epan/oui.h>
28 #include <epan/dissectors/packet-dcerpc.h>
29  
30 #include "packet-pn.h"
31  
32 void proto_register_pn_ptcp(void);
33 void proto_reg_handoff_pn_ptcp(void);
34  
35 static int proto_pn_ptcp = -1;
36  
37 static int hf_pn_ptcp_header = -1;
38 static int hf_pn_ptcp_block = -1;
39 static int hf_pn_ptcp_block_tlvheader = -1;
40  
41 static int hf_pn_ptcp_res1 = -1;
42 static int hf_pn_ptcp_res2 = -1;
43 static int hf_pn_ptcp_delay10ns = -1;
44 static int hf_pn_ptcp_seq_id = -1;
45 static int hf_pn_ptcp_delay1ns_byte = -1;
46 static int hf_pn_ptcp_delay1ns_fup = -1;
47 static int hf_pn_ptcp_delay1ns = -1;
48  
49 static int hf_pn_ptcp_tl_length = -1;
50 static int hf_pn_ptcp_tl_type = -1;
51  
52 static int hf_pn_ptcp_master_source_address = -1;
53 static int hf_pn_ptcp_subdomain_uuid = -1;
54  
55 static int hf_pn_ptcp_port_mac_address = -1;
56  
57 static int hf_pn_ptcp_t2portrxdelay = -1;
58 static int hf_pn_ptcp_t3porttxdelay = -1;
59  
60 static int hf_pn_ptcp_t2timestamp = -1;
61  
62 static int hf_pn_ptcp_epoch_number = -1;
63 static int hf_pn_ptcp_seconds = -1;
64 static int hf_pn_ptcp_nanoseconds = -1;
65  
66 static int hf_pn_ptcp_flags = -1;
67 static int hf_pn_ptcp_currentutcoffset = -1;
68  
69 static int hf_pn_ptcp_master_priority1 = -1;
70 static int hf_pn_ptcp_master_priority_level = -1;
71 static int hf_pn_ptcp_master_priority1_res = -1;
72 static int hf_pn_ptcp_master_priority1_act =-1;
73  
74 static int hf_pn_ptcp_master_priority2 = -1;
75 static int hf_pn_ptcp_clock_class = -1;
76 static int hf_pn_ptcp_clock_accuracy = -1;
77 static int hf_pn_ptcp_clockvariance = -1;
78  
79 static int hf_pn_ptcp_oui = -1;
80 static int hf_pn_ptcp_profinet_subtype = -1;
81 static int hf_pn_ptcp_irdata_uuid = -1;
82  
83 static gint ett_pn_ptcp = -1;
84 static gint ett_pn_ptcp_header = -1;
85 static gint ett_pn_ptcp_block = -1;
86 static gint ett_pn_ptcp_block_header = -1;
87  
88 #define OUI_PROFINET_MULTICAST 0x010ECF /* PROFIBUS Nutzerorganisation e.V. */
89  
90  
91 #define PN_PTCP_BT_END 0x00
92 #define PN_PTCP_BT_SUBDOMAIN 0x01
93 #define PN_PTCP_BT_TIME 0x02
94 #define PN_PTCP_BT_TIME_EXTENSION 0x03
95 #define PN_PTCP_BT_MASTER 0x04
96 #define PN_PTCP_BT_PORT_PARAMETER 0x05
97 #define PN_PTCP_BT_DELAY_PARAMETER 0x06
98 #define PN_PTCP_BT_PORT_TIME 0x07
99 #define PN_PTCP_BT_OPTION 0x7F
100 #define PN_PTCP_BT_RTDATA 0x7F
101  
102  
103 static const value_string pn_ptcp_block_type[] = {
104 { PN_PTCP_BT_END, "End" },
105 { PN_PTCP_BT_SUBDOMAIN, "Subdomain"},
106 { PN_PTCP_BT_TIME, "Time"},
107 { PN_PTCP_BT_TIME_EXTENSION, "TimeExtension"},
108 { PN_PTCP_BT_MASTER, "Master"},
109 { PN_PTCP_BT_PORT_PARAMETER, "PortParameter"},
110 { PN_PTCP_BT_DELAY_PARAMETER, "DelayParameter"},
111 { PN_PTCP_BT_PORT_TIME, "PortTime"},
112 /*0x08 - 0x7E Reserved */
113 { PN_PTCP_BT_OPTION, "Organizationally Specific"},
114 { 0, NULL }
115 };
116  
117 static const value_string pn_ptcp_oui_vals[] = {
118 { OUI_PROFINET, "PROFINET" },
119 { OUI_PROFINET_MULTICAST, "PROFINET" },
120 { 0, NULL }
121 };
122  
123 static const value_string pn_ptcp_master_prio1_vals[] = {
124 { 0x00, "Sync slave" },
125 { 0x01, "Primary master" },
126 { 0x02, "Secondary master" },
127 { 0x03, "Reserved" },
128 { 0x04, "Reserved" },
129 { 0x05, "Reserved" },
130 { 0x06, "Reserved" },
131 { 0x07, "Reserved" },
132 { 0, NULL }
133 };
134  
135 static const value_string pn_ptcp_master_prio1_levels[] = {
136 { 0x00, "Level 0 (highest)" },
137 { 0x01, "Level 1" },
138 { 0x02, "Level 2" },
139 { 0x03, "Level 3" },
140 { 0x04, "Level 4" },
141 { 0x05, "Level 5" },
142 { 0x06, "Level 6" },
143 { 0x07, "Level 7 (lowest)" },
144 { 0, NULL }
145 };
146  
147 static const value_string pn_ptcp_master_prio1_vals_active[] = {
148 { 0x00, "inactive" },
149 { 0x01, "active" },
150 { 0, NULL }
151 };
152  
153 #if 0
154 static const value_string pn_ptcp_master_prio1_short_vals[] = {
155 { 0x01, "Primary" },
156 { 0x02, "Secondary" },
157 { 0, NULL }
158 };
159 #endif
160  
161 static const value_string pn_ptcp_master_prio2_vals[] = {
162 { 0xFF, "Default" },
163 { 0, NULL }
164 };
165  
166 static const value_string pn_ptcp_clock_class_vals[] = {
167 { 0xFF, "Slave-only clock" },
168 { 0, NULL }
169 };
170  
171 static const value_string pn_ptcp_clock_accuracy_vals[] = {
172 { 0x20, "25ns" },
173 { 0x21, "100ns (Default)" },
174 { 0x22, "250ns" },
175 { 0x23, "1us" },
176 { 0x24, "2.5us" },
177 { 0x25, "10us" },
178 { 0x26, "25us" },
179 { 0x27, "100us" },
180 { 0x28, "250us" },
181 { 0x29, "1ms" },
182 { 0xFE, "Unknown" },
183 { 0, NULL }
184 };
185  
186 static const value_string pn_ptcp_profinet_subtype_vals[] = {
187 { 0x01, "RTData" },
188 { 0, NULL }
189 };
190  
191  
192  
193  
194 static int
195 dissect_PNPTCP_TLVHeader(tvbuff_t *tvb, int offset,
196 packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint16 *type, guint16 *length)
197 {
198 guint16 tl_type;
199 guint16 tl_length;
200  
201  
202 /* Type */
203 dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_ptcp_tl_type, &tl_type);
204 *type = tl_type >> 9;
205  
206 /* Length */
207 offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_ptcp_tl_length, &tl_length);
208 *length = tl_length & 0x1FF;
209  
210 return offset;
211 }
212  
213  
214 static int
215 dissect_PNPTCP_Subdomain(tvbuff_t *tvb, int offset,
216 packet_info *pinfo, proto_tree *tree, proto_item *item, guint16 u16FrameID)
217 {
218 guint8 mac[6];
219 e_guid_t uuid;
220  
221  
222 /* MasterSourceAddress */
223 offset = dissect_pn_mac(tvb, offset, pinfo, tree, hf_pn_ptcp_master_source_address, mac);
224  
225 /* SubdomainUUID */
226 offset = dissect_pn_uuid(tvb, offset, pinfo, tree, hf_pn_ptcp_subdomain_uuid, &uuid);
227  
228 if ((u16FrameID == 0xff00) || (u16FrameID == 0xff01)) {
229 col_append_fstr(pinfo->cinfo, COL_INFO, ", Master=%02x:%02x:%02x:%02x:%02x:%02x",
230 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
231 }
232  
233 proto_item_append_text(item, ": MasterSource=%02x:%02x:%02x:%02x:%02x:%02x",
234 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
235  
236 proto_item_append_text(item, ", Subdomain=%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
237 uuid.data1, uuid.data2, uuid.data3,
238 uuid.data4[0], uuid.data4[1],
239 uuid.data4[2], uuid.data4[3],
240 uuid.data4[4], uuid.data4[5],
241 uuid.data4[6], uuid.data4[7]);
242  
243 return offset;
244 }
245  
246  
247 static int
248 dissect_PNPTCP_Time(tvbuff_t *tvb, int offset,
249 packet_info *pinfo, proto_tree *tree, proto_item *item)
250 {
251 guint16 EpochNumber;
252 guint32 Seconds;
253 guint32 NanoSeconds;
254  
255  
256 /* EpochNumber */
257 offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_ptcp_epoch_number, &EpochNumber);
258  
259 /* Seconds */
260 offset = dissect_pn_uint32(tvb, offset, pinfo, tree, hf_pn_ptcp_seconds, &Seconds);
261  
262 /* NanoSeconds */
263 offset = dissect_pn_uint32(tvb, offset, pinfo, tree, hf_pn_ptcp_nanoseconds, &NanoSeconds);
264  
265 proto_item_append_text(item, ": Seconds=%u NanoSeconds=%u EpochNumber=%u",
266 Seconds, NanoSeconds, EpochNumber);
267  
268 col_append_fstr(pinfo->cinfo, COL_INFO, ", Time: %4us %09uns, Epoch: %u",
269 Seconds, NanoSeconds, EpochNumber);
270  
271 return offset;
272 }
273  
274  
275 static int
276 dissect_PNPTCP_TimeExtension(tvbuff_t *tvb, int offset,
277 packet_info *pinfo, proto_tree *tree, proto_item *item)
278 {
279 guint16 Flags;
280 guint16 CurrentUTCOffset;
281  
282  
283 /* Flags */
284 offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_ptcp_flags, &Flags);
285  
286 /* CurrentUTCOffset */
287 offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_ptcp_currentutcoffset, &CurrentUTCOffset);
288  
289 /* Padding */
290 offset = dissect_pn_align4(tvb, offset, pinfo, tree);
291  
292 proto_item_append_text(item, ": Flags=0x%x, CurrentUTCOffset=%u", Flags, CurrentUTCOffset);
293  
294 return offset;
295 }
296  
297  
298 static int
299 dissect_PNPTCP_Master(tvbuff_t *tvb, int offset,
300 packet_info *pinfo, proto_tree *tree, proto_item *item)
301 {
302 guint8 MasterPriority1;
303 guint8 MasterPriority2;
304 guint8 ClockClass;
305 guint8 ClockAccuracy;
306 gint16 ClockVariance;
307  
308  
309 /* MasterPriority1 is a bit field */
310 /* Bit 0 - 2: PTCP_MasterPriority1.Priority */
311 dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_master_priority1, &MasterPriority1);
312 /* Bit 3 - 5: PTCP_MasterPriority1.Level */
313 dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_master_priority_level, &MasterPriority1);
314 /* Bit 6: PTCP_MasterPriority1.Reserved */
315 dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_master_priority1_res, &MasterPriority1);
316 /* Bit 7: PTCP_MasterPriority1.Active */
317 offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_master_priority1_act, &MasterPriority1);
318  
319 /* MasterPriority2 */
320 offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_master_priority2, &MasterPriority2);
321  
322 /* ClockClass */
323 offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_clock_class, &ClockClass);
324  
325 /* ClockAccuracy */
326 offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_clock_accuracy, &ClockAccuracy);
327  
328 /* ClockVariance */
329 offset = dissect_pn_int16(tvb, offset, pinfo, tree, hf_pn_ptcp_clockvariance, &ClockVariance);
330  
331 /* Padding */
332 offset = dissect_pn_align4(tvb, offset, pinfo, tree);
333  
334 col_append_fstr(pinfo->cinfo, COL_INFO, ", Prio1=\"%s\"",
335 val_to_str(MasterPriority1 & 0x7, pn_ptcp_master_prio1_vals, "(Reserved: 0x%x)"));
336  
337 if ((MasterPriority1 & 0x80) == 0) {
338 proto_item_append_text(item, ": Prio1=\"%s\", Prio2=%s, Clock: Class=\"%s\", Accuracy=%s, Variance=%d",
339 val_to_str(MasterPriority1 & 0x7, pn_ptcp_master_prio1_vals, "(Reserved: 0x%x)"),
340 val_to_str(MasterPriority2, pn_ptcp_master_prio2_vals, "(Reserved: 0x%x)"),
341 val_to_str(ClockClass, pn_ptcp_clock_class_vals, "(Reserved: 0x%x)"),
342 val_to_str(ClockAccuracy, pn_ptcp_clock_accuracy_vals, "(Reserved: 0x%x)"),
343 ClockVariance);
344 }
345 else {
346 col_append_str(pinfo->cinfo, COL_INFO, " active");
347 proto_item_append_text(item, ": Prio1=\"%s\" is active, Prio2=%s, Clock: Class=\"%s\", Accuracy=%s, Variance=%d",
348 val_to_str(MasterPriority1 & 0x7, pn_ptcp_master_prio1_vals, "(Reserved: 0x%x)"),
349 val_to_str(MasterPriority2, pn_ptcp_master_prio2_vals, "(Reserved: 0x%x)"),
350 val_to_str(ClockClass, pn_ptcp_clock_class_vals, "(Reserved: 0x%x)"),
351 val_to_str(ClockAccuracy, pn_ptcp_clock_accuracy_vals, "(Reserved: 0x%x)"),
352 ClockVariance);
353 }
354  
355  
356 return offset;
357 }
358  
359  
360 static int
361 dissect_PNPTCP_PortParameter(tvbuff_t *tvb, int offset,
362 packet_info *pinfo, proto_tree *tree, proto_item *item)
363 {
364 guint32 t2portrxdelay;
365 guint32 t3porttxdelay;
366  
367  
368 /* Padding */
369 offset = dissect_pn_align4(tvb, offset, pinfo, tree);
370  
371 /* T2PortRxDelay */
372 offset = dissect_pn_uint32(tvb, offset, pinfo, tree, hf_pn_ptcp_t2portrxdelay, &t2portrxdelay);
373  
374 /* T3PortTxDelay */
375 offset = dissect_pn_uint32(tvb, offset, pinfo, tree, hf_pn_ptcp_t3porttxdelay, &t3porttxdelay);
376  
377 proto_item_append_text(item, ": T2PortRxDelay=%uns, T3PortTxDelay=%uns",
378 t2portrxdelay, t3porttxdelay);
379  
380 col_append_fstr(pinfo->cinfo, COL_INFO, ", T2Rx=%uns, T3Tx=%uns",
381 t2portrxdelay, t3porttxdelay);
382  
383 return offset;
384 }
385  
386  
387 static int
388 dissect_PNPTCP_DelayParameter(tvbuff_t *tvb, int offset,
389 packet_info *pinfo, proto_tree *tree, proto_item *item)
390 {
391 guint8 mac[6];
392  
393  
394 /* PortMACAddress */
395 offset = dissect_pn_mac(tvb, offset, pinfo, tree, hf_pn_ptcp_port_mac_address, mac);
396  
397 /* Padding */
398 offset = dissect_pn_align4(tvb, offset, pinfo, tree);
399  
400  
401 proto_item_append_text(item, ": PortMAC=%02x:%02x:%02x:%02x:%02x:%02x",
402 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
403  
404 col_append_fstr(pinfo->cinfo, COL_INFO, ", PortMAC=%02x:%02x:%02x:%02x:%02x:%02x",
405 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
406  
407 return offset;
408 }
409  
410  
411 static int
412 dissect_PNPTCP_PortTime(tvbuff_t *tvb, int offset,
413 packet_info *pinfo, proto_tree *tree, proto_item *item)
414 {
415 guint32 t2timestamp;
416  
417  
418 /* Padding */
419 offset = dissect_pn_align4(tvb, offset, pinfo, tree);
420  
421 /* T2TimeStamp */
422 offset = dissect_pn_uint32(tvb, offset, pinfo, tree, hf_pn_ptcp_t2timestamp, &t2timestamp);
423  
424 proto_item_append_text(item, ": T2TimeStamp=%uns", t2timestamp);
425  
426 col_append_fstr(pinfo->cinfo, COL_INFO, ", T2TS=%uns", t2timestamp);
427  
428 return offset;
429 }
430  
431  
432 static int
433 dissect_PNPTCP_Option_PROFINET(tvbuff_t *tvb, int offset,
434 packet_info *pinfo, proto_tree *tree, proto_item *item, guint16 length)
435 {
436 guint8 subType;
437 e_guid_t uuid;
438  
439 /* OUI already dissected! */
440  
441 /* SubType */
442 offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_profinet_subtype, &subType);
443 length -= 1;
444  
445 switch (subType) {
446 case 1: /* RTData */
447 /* Padding */
448 offset = dissect_pn_align4(tvb, offset, pinfo, tree);
449  
450 /* IRDataUUID */
451 offset = dissect_pn_uuid(tvb, offset, pinfo, tree, hf_pn_ptcp_irdata_uuid, &uuid);
452 proto_item_append_text(item, ": IRDataUUID=%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
453 uuid.data1, uuid.data2, uuid.data3,
454 uuid.data4[0], uuid.data4[1],
455 uuid.data4[2], uuid.data4[3],
456 uuid.data4[4], uuid.data4[5],
457 uuid.data4[6], uuid.data4[7]);
458  
459 break;
460 default:
461 offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, length);
462 break;
463 }
464  
465 return offset;
466 }
467  
468  
469 static int
470 dissect_PNPTCP_Option(tvbuff_t *tvb, int offset,
471 packet_info *pinfo, proto_tree *tree, proto_item *item, guint16 length)
472 {
473 guint32 oui;
474  
475  
476 /* verify remaining TLV length */
477 if (length < 4)
478 {
479 /* too short */
480 offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, length);
481 return (offset);
482 }
483  
484 /* OUI (organizational unique id) */
485 offset = dissect_pn_oid(tvb, offset, pinfo,tree, hf_pn_ptcp_oui, &oui);
486 length -= 3;
487  
488 switch (oui)
489 {
490 case OUI_PROFINET:
491 case OUI_PROFINET_MULTICAST:
492 proto_item_append_text(item, ": PROFINET");
493 offset = dissect_PNPTCP_Option_PROFINET(tvb, offset, pinfo, tree, item, length);
494 break;
495 default:
496 /* SubType */
497 offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, length);
498 }
499  
500 return (offset);
501 }
502  
503  
504 static int
505 dissect_PNPTCP_block(tvbuff_t *tvb, int offset,
506 packet_info *pinfo, proto_tree *tree, proto_item *item _U_, gboolean *end, guint16 u16FrameID)
507 {
508 guint16 type;
509 guint16 length;
510  
511 proto_item *sub_item;
512 proto_tree *sub_tree;
513 proto_item *tlvheader_item;
514 proto_tree *tlvheader_tree;
515 guint32 u32SubStart;
516  
517  
518 *end = FALSE;
519  
520 /* block subtree */
521 sub_item = proto_tree_add_item(tree, hf_pn_ptcp_block, tvb, offset, 0, ENC_NA);
522 sub_tree = proto_item_add_subtree(sub_item, ett_pn_ptcp_block);
523 u32SubStart = offset;
524  
525 /* tlvheader subtree */
526 tlvheader_item = proto_tree_add_item(sub_tree, hf_pn_ptcp_block_tlvheader, tvb, offset, 2 /* len */, ENC_NA);
527 tlvheader_tree = proto_item_add_subtree(tlvheader_item, ett_pn_ptcp_block_header);
528  
529 offset = dissect_PNPTCP_TLVHeader(tvb, offset, pinfo, tlvheader_tree, sub_item, &type, &length);
530  
531 proto_item_set_text(sub_item, "%s",
532 val_to_str(type, pn_ptcp_block_type, "Unknown"));
533  
534 proto_item_append_text(tlvheader_item, ": Type=%s (%x), Length=%u",
535 val_to_str(type, pn_ptcp_block_type, "Unknown"), type, length);
536  
537 switch (type) {
538 case 0x00: /* End, no content */
539 *end = TRUE;
540 break;
541 case 0x01: /* Subdomain */
542 dissect_PNPTCP_Subdomain(tvb, offset, pinfo, sub_tree, sub_item, u16FrameID);
543 break;
544 case 0x02: /* Time */
545 dissect_PNPTCP_Time(tvb, offset, pinfo, sub_tree, sub_item);
546 break;
547 case 0x03: /* TimeExtension */
548 dissect_PNPTCP_TimeExtension(tvb, offset, pinfo, sub_tree, sub_item);
549 break;
550 case 0x04: /* Master */
551 dissect_PNPTCP_Master(tvb, offset, pinfo, sub_tree, sub_item);
552 break;
553 case 0x05: /* PortParameter */
554 dissect_PNPTCP_PortParameter(tvb, offset, pinfo, sub_tree, sub_item);
555 break;
556 case 0x06: /* DelayParameter */
557 dissect_PNPTCP_DelayParameter(tvb, offset, pinfo, sub_tree, sub_item);
558 break;
559 case 0x07: /* PortTime */
560 dissect_PNPTCP_PortTime(tvb, offset, pinfo, sub_tree, sub_item);
561 break;
562 case 0x7F: /* Organizational Specific */
563 dissect_PNPTCP_Option(tvb, offset, pinfo, sub_tree, sub_item, length);
564 break;
565 default:
566 offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, length);
567 }
568 offset += length;
569  
570 proto_item_set_len(sub_item, offset - u32SubStart);
571  
572 return offset;
573 }
574  
575  
576 static int
577 dissect_PNPTCP_blocks(tvbuff_t *tvb, int offset,
578 packet_info *pinfo, proto_tree *tree, proto_item *item, guint16 u16FrameID)
579 {
580 gboolean end = FALSE;
581  
582 /* as long as we have some bytes, try a new block */
583 while (!end) {
584 offset = dissect_PNPTCP_block(tvb, offset, pinfo, tree, item, &end, u16FrameID);
585 }
586  
587 return offset;
588 }
589  
590  
591 static int
592 dissect_PNPTCP_FollowUpPDU(tvbuff_t *tvb, int offset,
593 packet_info *pinfo, proto_tree *tree, proto_item *item, guint16 u16FrameID,
594 const char *name, const char *name_short)
595 {
596 proto_item *header_item;
597 proto_tree *header_tree;
598 guint16 seq_id;
599 gint32 delay1ns_fup;
600  
601  
602 /* dissect the header */
603 header_item = proto_tree_add_item(tree, hf_pn_ptcp_header, tvb, offset, 20 /* len */, ENC_NA);
604 header_tree = proto_item_add_subtree(header_item, ett_pn_ptcp_header);
605  
606 /* Padding 12 bytes */
607 offset = dissect_pn_padding(tvb, offset, pinfo, header_tree, 12);
608  
609 /* SequenceID */
610 offset = dissect_pn_uint16(tvb, offset, pinfo, header_tree, hf_pn_ptcp_seq_id, &seq_id);
611  
612 /* Padding */
613 offset = dissect_pn_align4(tvb, offset, pinfo, header_tree);
614  
615 /* Delay1ns_FUP */
616 offset = dissect_pn_int32(tvb, offset, pinfo, header_tree, hf_pn_ptcp_delay1ns_fup, &delay1ns_fup);
617  
618 col_append_fstr(pinfo->cinfo, COL_INFO, "%s, Seq=%3u, Delay=%11dns", name, seq_id, delay1ns_fup);
619 proto_item_append_text(item, "%s: Sequence=%u, Delay=%dns", name_short, seq_id, delay1ns_fup);
620 proto_item_append_text(header_item, ": Sequence=%u, Delay=%dns", seq_id, delay1ns_fup);
621  
622  
623 /* dissect the TLV blocks */
624 offset = dissect_PNPTCP_blocks(tvb, offset, pinfo, tree, item, u16FrameID);
625  
626 return offset;
627 }
628  
629  
630 static int
631 dissect_PNPTCP_RTSyncPDU(tvbuff_t *tvb, int offset,
632 packet_info *pinfo, proto_tree *tree, proto_item *item, guint16 u16FrameID,
633 const char *name, const char *name_short)
634 {
635 proto_item *header_item;
636 proto_tree *header_tree;
637 guint32 res_1;
638 guint32 res_2;
639 guint32 delay10ns;
640 guint16 seq_id;
641 guint8 delay1ns_8;
642 guint64 delay1ns_64;
643 guint32 delay1ns_32;
644 guint32 delayms;
645  
646  
647 header_item = proto_tree_add_item(tree, hf_pn_ptcp_header, tvb, offset, 20 /* len */, ENC_NA);
648 header_tree = proto_item_add_subtree(header_item, ett_pn_ptcp_header);
649  
650 /* Reserved_1 */
651 offset = dissect_pn_uint32(tvb, offset, pinfo, header_tree, hf_pn_ptcp_res1, &res_1);
652  
653 /* Reserved_2 */
654 offset = dissect_pn_uint32(tvb, offset, pinfo, header_tree, hf_pn_ptcp_res2, &res_2);
655  
656 /* Delay10ns */
657 offset = dissect_pn_uint32(tvb, offset, pinfo, header_tree, hf_pn_ptcp_delay10ns, &delay10ns);
658  
659 /* SequenceID */
660 offset = dissect_pn_uint16(tvb, offset, pinfo, header_tree, hf_pn_ptcp_seq_id, &seq_id);
661  
662 /* Delay1ns */
663 offset = dissect_pn_uint8(tvb, offset, pinfo, header_tree, hf_pn_ptcp_delay1ns_byte, &delay1ns_8);
664  
665 /* Padding */
666 offset = dissect_pn_align4(tvb, offset, pinfo, header_tree);
667  
668 /* Delay1ns */
669 offset = dissect_pn_uint32(tvb, offset, pinfo, header_tree, hf_pn_ptcp_delay1ns, &delay1ns_32);
670  
671 /* Padding */
672 offset = dissect_pn_align4(tvb, offset, pinfo, tree);
673  
674  
675 delay1ns_64 = ((guint64) delay10ns) * 10 + delay1ns_8 + delay1ns_32;
676 delayms = (guint32) (delay1ns_64 / (1000 * 1000));
677  
678 col_append_fstr(pinfo->cinfo, COL_INFO, "%s, Seq=%3u, Delay=%11" G_GINT64_MODIFIER "uns",
679 name, seq_id, delay1ns_64);
680 proto_item_append_text(item, "%s: Sequence=%u, Delay=%" G_GINT64_MODIFIER "uns",
681 name_short, seq_id, delay1ns_64);
682 proto_item_append_text(header_item, ": Sequence=%u, Delay=%" G_GINT64_MODIFIER "uns",
683 seq_id, delay1ns_64);
684  
685 if (delay1ns_64 != 0)
686 proto_item_append_text(header_item, " (%u.%03u,%03u,%03u sec)",
687 delayms / 1000,
688 delayms % 1000,
689 (delay10ns % (1000*100)) / 100,
690 delay10ns % 100 * 10 + delay1ns_8);
691  
692 /* dissect the PDU */
693 offset = dissect_PNPTCP_blocks(tvb, offset, pinfo, tree, item, u16FrameID);
694  
695 return offset;
696 }
697  
698  
699 static int
700 dissect_PNPTCP_AnnouncePDU(tvbuff_t *tvb, int offset,
701 packet_info *pinfo, proto_tree *tree, proto_item *item, guint16 u16FrameID,
702 const char *name, const char *name_short)
703 {
704 proto_item *header_item;
705 proto_tree *header_tree;
706 guint16 seq_id;
707  
708  
709 /* dissect the header */
710 header_item = proto_tree_add_item(tree, hf_pn_ptcp_header, tvb, offset, 20 /* len */, ENC_NA);
711 header_tree = proto_item_add_subtree(header_item, ett_pn_ptcp_header);
712  
713 /* Padding 12 bytes */
714 offset = dissect_pn_padding(tvb, offset, pinfo, header_tree, 12);
715  
716 /* SequenceID */
717 offset = dissect_pn_uint16(tvb, offset, pinfo, header_tree, hf_pn_ptcp_seq_id, &seq_id);
718  
719 /* Padding 6 bytes */
720 offset = dissect_pn_padding(tvb, offset, pinfo, header_tree, 6);
721  
722 col_append_fstr(pinfo->cinfo, COL_INFO, "%s, Seq=%3u", name, seq_id);
723 proto_item_append_text(item, "%s: Sequence=%u", name_short, seq_id);
724 proto_item_append_text(header_item, ": Sequence=%u", seq_id);
725  
726  
727 /* dissect the PDU */
728 offset = dissect_PNPTCP_blocks(tvb, offset, pinfo, tree, item, u16FrameID);
729  
730 return offset;
731 }
732  
733  
734 static int
735 dissect_PNPTCP_DelayPDU(tvbuff_t *tvb, int offset,
736 packet_info *pinfo, proto_tree *tree, proto_item *item, guint16 u16FrameID,
737 const char *name, const char *name_short)
738 {
739 proto_item *header_item;
740 proto_tree *header_tree;
741 guint16 seq_id;
742 guint32 delay1ns;
743  
744  
745 /* dissect the header */
746 header_item = proto_tree_add_item(tree, hf_pn_ptcp_header, tvb, offset, 20 /* len */, ENC_NA);
747 header_tree = proto_item_add_subtree(header_item, ett_pn_ptcp_header);
748  
749 /* Padding 12 bytes */
750 offset = dissect_pn_padding(tvb, offset, pinfo, header_tree, 12);
751  
752 /* SequenceID */
753 offset = dissect_pn_uint16(tvb, offset, pinfo, header_tree, hf_pn_ptcp_seq_id, &seq_id);
754  
755 /* Padding */
756 offset = dissect_pn_align4(tvb, offset, pinfo, header_tree);
757  
758 /* Delay1ns_FUP */
759 offset = dissect_pn_uint32(tvb, offset, pinfo, header_tree, hf_pn_ptcp_delay1ns, &delay1ns);
760  
761 col_append_fstr(pinfo->cinfo, COL_INFO, "%s, Seq=%3u, Delay=%11uns", name, seq_id, delay1ns);
762 proto_item_append_text(item, "%s: Sequence=%u, Delay=%uns", name_short, seq_id, delay1ns);
763 proto_item_append_text(header_item, ": Sequence=%u, Delay=%uns", seq_id, delay1ns);
764  
765  
766 /* dissect the PDU */
767 offset = dissect_PNPTCP_blocks(tvb, offset, pinfo, tree, item, u16FrameID);
768  
769 return offset;
770 }
771  
772  
773 /* possibly dissect a PN-RT packet (frame ID must be in the appropriate range) */
774 static gboolean
775 dissect_PNPTCP_Data_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
776 {
777 /* the tvb will NOT contain the frame_id here, so get it from dissector data! */
778 guint16 u16FrameID = GPOINTER_TO_UINT(data);
779 proto_item *item;
780 proto_tree *ptcp_tree;
781 int offset = 0;
782 guint32 u32SubStart;
783  
784  
785 /* frame id must be in valid range (acyclic Real-Time, PTCP) */
786 /* 0x0000 - 0x007F: RTSyncPDU (with follow up) */
787 /* 0x0080 - 0x00FF: RTSyncPDU (without follow up) */
788 /* 0xFF00 - 0xFF1F: AnnouncePDU */
789 /* 0xFF20 - 0xFF3F: FollowUpPDU */
790 /* 0xFF40 - 0xFF5F: Delay...PDU */
791 if ( ((u16FrameID >= 0x0100) && (u16FrameID < 0xFF00)) || (u16FrameID > 0xFF5F) ) {
792 /* we are not interested in this packet */
793 return FALSE;
794 }
795  
796 col_set_str(pinfo->cinfo, COL_PROTOCOL, "PN-PTCP");
797 col_clear(pinfo->cinfo, COL_INFO);
798  
799 /* subtree for PTCP */
800 item = proto_tree_add_protocol_format(tree, proto_pn_ptcp, tvb, 0, 0, "PROFINET PTCP, ");
801 ptcp_tree = proto_item_add_subtree(item, ett_pn_ptcp);
802 u32SubStart = offset;
803  
804 switch (u16FrameID) {
805 /* range 1 (0x0000 - 0x007F) */
806 /* 0x0000 - 0x001F reserved */
807 case 0x0020:
808 offset = dissect_PNPTCP_RTSyncPDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID,
809 "RTSync FU (Clock)", "RTSync FU (Clock)");
810 break;
811 case 0x0021:
812 offset = dissect_PNPTCP_RTSyncPDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID,
813 "RTSync FU (Time)", "RTSync FU (Time)");
814 break;
815 /* 0x0022 - 0x007F reserved */
816  
817 /* range 2 (0x0080 - 0x00FF) */
818 case 0x0080:
819 offset = dissect_PNPTCP_RTSyncPDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID,
820 "RTSync (Clock)", "RTSync (Clock)");
821 break;
822 case 0x0081:
823 offset = dissect_PNPTCP_RTSyncPDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID,
824 "RTSync (Time)", "RTSync (Time)");
825 break;
826 /* 0x0081 - 0x00FF reserved */
827  
828 /* range 7 (0xFF00 - 0xFF5F) */
829 case 0xff00:
830 offset = dissect_PNPTCP_AnnouncePDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID,
831 "Announce (Clock)", "Announce (Clock)");
832 break;
833 case 0xff01:
834 offset = dissect_PNPTCP_AnnouncePDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID,
835 "Announce (Time)", "Announce (Time)");
836 break;
837 /* 0xFF02 - 0xFF1F reserved */
838 case 0xff20:
839 offset = dissect_PNPTCP_FollowUpPDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID,
840 "FollowUp (Clock)", "FollowUp (Clock)");
841 break;
842 case 0xff21:
843 offset = dissect_PNPTCP_FollowUpPDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID,
844 "FollowUp (Time)", "FollowUp (Time)");
845 break;
846 /* 0xFF22 - 0xFF3F reserved */
847 case 0xff40:
848 offset = dissect_PNPTCP_DelayPDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID,
849 "DelayReq ", "DelayReq");
850 break;
851 case 0xff41:
852 offset = dissect_PNPTCP_DelayPDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID,
853 "DelayRes ", "DelayRes");
854 break;
855 case 0xff42:
856 offset = dissect_PNPTCP_DelayPDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID,
857 "DelayFuRes ", "DelayFuRes");
858 break;
859 case 0xff43:
860 offset = dissect_PNPTCP_DelayPDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID,
861 "DelayRes ", "DelayRes");
862 break;
863 /* 0xFF44 - 0xFF5F reserved */
864 default:
865 offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, tvb_captured_length_remaining(tvb, offset));
866  
867 col_append_fstr(pinfo->cinfo, COL_INFO, "Reserved FrameID 0x%04x", u16FrameID);
868  
869 proto_item_append_text(item, "Reserved FrameID 0x%04x", u16FrameID);
870  
871 offset += tvb_captured_length_remaining(tvb, offset);
872 break;
873 }
874  
875 proto_item_set_len(item, offset - u32SubStart);
876  
877 return TRUE;
878 }
879  
880  
881 void
882 proto_register_pn_ptcp (void)
883 {
884 static hf_register_info hf[] = {
885 { &hf_pn_ptcp_header,
886 { "Header", "pn_ptcp.header",
887 FT_NONE, BASE_NONE, NULL, 0x0,
888 NULL, HFILL }},
889  
890 { &hf_pn_ptcp_block,
891 { "Block", "pn_ptcp.block",
892 FT_NONE, BASE_NONE, NULL, 0x0,
893 NULL, HFILL }},
894  
895 { &hf_pn_ptcp_block_tlvheader,
896 { "TLVHeader", "pn_ptcp.tlvheader",
897 FT_NONE, BASE_NONE, NULL, 0x0,
898 NULL, HFILL }},
899  
900  
901 { &hf_pn_ptcp_res1,
902 { "Reserved 1", "pn_ptcp.res1",
903 FT_UINT32, BASE_DEC, NULL, 0x0,
904 NULL, HFILL }},
905  
906 { &hf_pn_ptcp_res2,
907 { "Reserved 2", "pn_ptcp.res2",
908 FT_UINT32, BASE_DEC, NULL, 0x0,
909 NULL, HFILL }},
910  
911 { &hf_pn_ptcp_delay10ns,
912 { "Delay10ns", "pn_ptcp.delay10ns",
913 FT_UINT32, BASE_DEC, NULL, 0x0,
914 NULL, HFILL }},
915  
916 { &hf_pn_ptcp_seq_id,
917 { "SequenceID", "pn_ptcp.sequence_id",
918 FT_UINT16, BASE_DEC, NULL, 0x0,
919 NULL, HFILL }},
920  
921 { &hf_pn_ptcp_delay1ns_byte,
922 { "Delay1ns_Byte", "pn_ptcp.delay1ns_byte",
923 FT_UINT8, BASE_DEC, NULL, 0x0,
924 NULL, HFILL }},
925  
926 { &hf_pn_ptcp_delay1ns,
927 { "Delay1ns", "pn_ptcp.delay1ns",
928 FT_UINT32, BASE_DEC, NULL, 0x0,
929 NULL, HFILL }},
930  
931 { &hf_pn_ptcp_delay1ns_fup,
932 { "Delay1ns_FUP", "pn_ptcp.delay1ns_fup",
933 FT_INT32, BASE_DEC, NULL, 0x0,
934 NULL, HFILL }},
935  
936  
937 { &hf_pn_ptcp_tl_length,
938 { "TypeLength.Length", "pn_ptcp.tl_length",
939 FT_UINT16, BASE_DEC, 0x0, 0x1FF,
940 NULL, HFILL }},
941  
942 { &hf_pn_ptcp_tl_type,
943 { "TypeLength.Type", "pn_ptcp.tl_type",
944 FT_UINT16, BASE_DEC, 0x0, 0xFE00,
945 NULL, HFILL }},
946  
947  
948 { &hf_pn_ptcp_master_source_address,
949 { "MasterSourceAddress", "pn_ptcp.master_source_address",
950 FT_ETHER, BASE_NONE, 0x0, 0x0,
951 NULL, HFILL }},
952  
953 { &hf_pn_ptcp_subdomain_uuid,
954 { "SubdomainUUID", "pn_ptcp.subdomain_uuid",
955 FT_GUID, BASE_NONE, 0x0, 0x0,
956 NULL, HFILL }},
957  
958  
959 { &hf_pn_ptcp_port_mac_address,
960 { "PortMACAddress", "pn_ptcp.port_mac_address",
961 FT_ETHER, BASE_NONE, 0x0, 0x0,
962 NULL, HFILL }},
963  
964  
965 { &hf_pn_ptcp_t2portrxdelay,
966 { "T2PortRxDelay (ns)", "pn_ptcp.t2portrxdelay",
967 FT_UINT32, BASE_DEC, 0x0, 0x0,
968 NULL, HFILL }},
969  
970 { &hf_pn_ptcp_t3porttxdelay,
971 { "T3PortTxDelay (ns)", "pn_ptcp.t3porttxdelay",
972 FT_UINT32, BASE_DEC, 0x0, 0x0,
973 NULL, HFILL }},
974  
975 { &hf_pn_ptcp_t2timestamp,
976 { "T2TimeStamp (ns)", "pn_ptcp.t2timestamp",
977 FT_UINT32, BASE_DEC, 0x0, 0x0,
978 NULL, HFILL }},
979  
980  
981 { &hf_pn_ptcp_epoch_number,
982 { "EpochNumber", "pn_ptcp.epoch_number",
983 FT_UINT16, BASE_DEC, 0x0, 0x0,
984 NULL, HFILL }},
985  
986 { &hf_pn_ptcp_seconds,
987 { "Seconds", "pn_ptcp.seconds",
988 FT_UINT32, BASE_DEC, 0x0, 0x0,
989 NULL, HFILL }},
990  
991 { &hf_pn_ptcp_nanoseconds,
992 { "NanoSeconds", "pn_ptcp.nanoseconds",
993 FT_UINT32, BASE_DEC, 0x0, 0x0,
994 NULL, HFILL }},
995  
996  
997 { &hf_pn_ptcp_flags,
998 { "Flags", "pn_ptcp.flags",
999 FT_UINT16, BASE_HEX, 0x0, 0x0,
1000 NULL, HFILL }},
1001  
1002 { &hf_pn_ptcp_currentutcoffset,
1003 { "CurrentUTCOffset", "pn_ptcp.currentutcoffset",
1004 FT_UINT16, BASE_DEC, 0x0, 0x0,
1005 NULL, HFILL }},
1006  
1007  
1008 { &hf_pn_ptcp_master_priority1,
1009 { "MasterPriority1.Priority", "pn_ptcp.master_priority1_prio",
1010 FT_UINT8, BASE_HEX, VALS(pn_ptcp_master_prio1_vals), 0x07,
1011 NULL, HFILL }},
1012  
1013 { &hf_pn_ptcp_master_priority_level,
1014 { "MasterPriority1.Level", "pn_ptcp.master_priority1_level",
1015 FT_UINT8, BASE_HEX, VALS(pn_ptcp_master_prio1_levels), 0x38,
1016 NULL, HFILL }},
1017  
1018 { &hf_pn_ptcp_master_priority1_res,
1019 { "MasterPriority1.Reserved", "pn_ptcp.master_priority1_res",
1020 FT_UINT8, BASE_HEX, 0x0, 0x40,
1021 NULL, HFILL }},
1022  
1023 { &hf_pn_ptcp_master_priority1_act,
1024 { "MasterPriority1.Active", "pn_ptcp.master_priority1_act",
1025 FT_UINT8, BASE_HEX, VALS(pn_ptcp_master_prio1_vals_active), 0x80,
1026 NULL, HFILL }},
1027  
1028 { &hf_pn_ptcp_master_priority2,
1029 { "MasterPriority2", "pn_ptcp.master_priority2",
1030 FT_UINT8, BASE_DEC, VALS(pn_ptcp_master_prio2_vals), 0x0,
1031 NULL, HFILL }},
1032  
1033 { &hf_pn_ptcp_clock_class,
1034 { "ClockClass", "pn_ptcp.clock_class",
1035 FT_UINT8, BASE_DEC, VALS(pn_ptcp_clock_class_vals), 0x0,
1036 NULL, HFILL }},
1037  
1038 { &hf_pn_ptcp_clock_accuracy,
1039 { "ClockAccuracy", "pn_ptcp.clock_accuracy",
1040 FT_UINT8, BASE_DEC, VALS(pn_ptcp_clock_accuracy_vals), 0x0,
1041 NULL, HFILL }},
1042  
1043 { &hf_pn_ptcp_clockvariance,
1044 { "ClockVariance", "pn_ptcp.clockvariance",
1045 FT_INT16, BASE_DEC, 0x0, 0x0,
1046 NULL, HFILL }},
1047  
1048  
1049 { &hf_pn_ptcp_oui,
1050 { "Organizationally Unique Identifier", "pn_ptcp.oui",
1051 FT_UINT24, BASE_HEX, VALS(pn_ptcp_oui_vals), 0x0,
1052 NULL, HFILL }},
1053  
1054 { &hf_pn_ptcp_profinet_subtype,
1055 { "Subtype", "pn_ptcp.subtype",
1056 FT_UINT8, BASE_HEX, VALS(pn_ptcp_profinet_subtype_vals), 0x0,
1057 "PROFINET Subtype", HFILL }},
1058  
1059  
1060 { &hf_pn_ptcp_irdata_uuid,
1061 { "IRDataUUID", "pn_ptcp.irdata_uuid",
1062 FT_GUID, BASE_NONE, 0x0, 0x0,
1063 NULL, HFILL }},
1064  
1065 };
1066  
1067 static gint *ett[] = {
1068 &ett_pn_ptcp,
1069 &ett_pn_ptcp_header,
1070 &ett_pn_ptcp_block,
1071 &ett_pn_ptcp_block_header
1072 };
1073 proto_pn_ptcp = proto_register_protocol ("PROFINET PTCP", "PN-PTCP", "pn_ptcp");
1074 proto_register_field_array (proto_pn_ptcp, hf, array_length (hf));
1075 proto_register_subtree_array (ett, array_length (ett));
1076 }
1077  
1078 void
1079 proto_reg_handoff_pn_ptcp (void)
1080 {
1081 /* register ourself as an heuristic pn-rt payload dissector */
1082 heur_dissector_add("pn_rt", dissect_PNPTCP_Data_heur, "PROFINET PTCP IO", "pn_ptcp_pn_rt", proto_pn_ptcp, HEURISTIC_ENABLE);
1083 }
1084  
1085 /*
1086 * Editor modelines - http://www.wireshark.org/tools/modelines.html
1087 *
1088 * Local variables:
1089 * c-basic-offset: 4
1090 * tab-width: 8
1091 * indent-tabs-mode: nil
1092 * End:
1093 *
1094 * vi: set shiftwidth=4 tabstop=8 expandtab:
1095 * :indentSize=4:tabSize=8:noTabs=true:
1096 */