We always HAVE_CONFIG_H so don't bother checking whether we have it or not.
[metze/wireshark/wip.git] / plugins / profinet / packet-pn-ptcp.c
1 /* packet-pn-ptcp.c
2  * Routines for PN-PTCP (PROFINET Precision Time Clock 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24  */
25
26 #include "config.h"
27
28
29 #include <glib.h>
30 #include <epan/packet.h>
31 #include <epan/dissectors/packet-dcerpc.h>
32 #include <epan/oui.h>
33
34 #include "packet-pn.h"
35
36
37
38 static int proto_pn_ptcp = -1;
39
40 static int hf_pn_ptcp_header = -1;
41 static int hf_pn_ptcp_block = -1;
42 static int hf_pn_ptcp_block_tlvheader = -1;
43
44 static int hf_pn_ptcp_res1 = -1;
45 static int hf_pn_ptcp_res2 = -1;
46 static int hf_pn_ptcp_delay10ns = -1;
47 static int hf_pn_ptcp_seq_id = -1;
48 static int hf_pn_ptcp_delay1ns_byte = -1;
49 static int hf_pn_ptcp_delay1ns_fup = -1;
50 static int hf_pn_ptcp_delay1ns = -1;
51
52 static int hf_pn_ptcp_tl_length = -1;
53 static int hf_pn_ptcp_tl_type = -1;
54
55 static int hf_pn_ptcp_master_source_address = -1;
56 static int hf_pn_ptcp_subdomain_uuid = -1;
57
58 static int hf_pn_ptcp_port_mac_address = -1;
59
60 static int hf_pn_ptcp_t2portrxdelay = -1;
61 static int hf_pn_ptcp_t3porttxdelay = -1;
62
63 static int hf_pn_ptcp_t2timestamp = -1;
64
65 static int hf_pn_ptcp_epoch_number = -1;
66 static int hf_pn_ptcp_seconds = -1;
67 static int hf_pn_ptcp_nanoseconds = -1;
68
69 static int hf_pn_ptcp_flags = -1;
70 static int hf_pn_ptcp_currentutcoffset = -1;
71
72 static int hf_pn_ptcp_master_priority1 = -1;
73 static int hf_pn_ptcp_master_priority2 = -1;
74 static int hf_pn_ptcp_clock_class = -1;
75 static int hf_pn_ptcp_clock_accuracy = -1;
76 static int hf_pn_ptcp_clockvariance = -1;
77
78 static int hf_pn_ptcp_oui = -1;
79 static int hf_pn_ptcp_profinet_subtype = -1;
80 static int hf_pn_ptcp_irdata_uuid = -1;
81
82 static gint ett_pn_ptcp = -1;
83 static gint ett_pn_ptcp_header = -1;
84 static gint ett_pn_ptcp_block = -1;
85 static gint ett_pn_ptcp_block_header = -1;
86
87 #define OUI_PROFINET_MULTICAST          0x010ECF        /* PROFIBUS Nutzerorganisation e.V. */
88
89
90 #define PN_PTCP_BT_END              0x00
91 #define PN_PTCP_BT_SUBDOMAIN        0x01
92 #define PN_PTCP_BT_TIME             0x02
93 #define PN_PTCP_BT_TIME_EXTENSION   0x03
94 #define PN_PTCP_BT_MASTER           0x04
95 #define PN_PTCP_BT_PORT_PARAMETER   0x05
96 #define PN_PTCP_BT_DELAY_PARAMETER  0x06
97 #define PN_PTCP_BT_PORT_TIME        0x07
98 #define PN_PTCP_BT_OPTION           0x7F
99 #define PN_PTCP_BT_RTDATA           0x7F
100
101
102 static const value_string pn_ptcp_block_type[] = {
103         { PN_PTCP_BT_END,               "End" },
104         { PN_PTCP_BT_SUBDOMAIN,         "Subdomain"},
105         { PN_PTCP_BT_TIME,              "Time"},
106         { PN_PTCP_BT_TIME_EXTENSION,    "TimeExtension"},
107         { PN_PTCP_BT_MASTER,            "Master"},
108         { PN_PTCP_BT_PORT_PARAMETER,    "PortParameter"},
109         { PN_PTCP_BT_DELAY_PARAMETER,   "DelayParameter"},
110         { PN_PTCP_BT_PORT_TIME,         "PortTime"},
111     /*0x08 - 0x7E Reserved */
112         { PN_PTCP_BT_OPTION,            "Organizationally Specific"},
113     { 0, NULL }
114 };
115
116 static const value_string pn_ptcp_oui_vals[] = {
117         { OUI_PROFINET,             "PROFINET" },
118         { OUI_PROFINET_MULTICAST,   "PROFINET" },
119         { 0, NULL }
120 };
121
122 static const value_string pn_ptcp_master_prio1_vals[] = {
123         { 0x01, "Primary sync. master" },
124         { 0x02, "Secondary sync. master" },
125         { 0, NULL }
126 };
127
128 static const value_string pn_ptcp_master_prio1_short_vals[] = {
129         { 0x01, "Primary" },
130         { 0x02, "Secondary" },
131         { 0, NULL }
132 };
133
134 static const value_string pn_ptcp_master_prio2_vals[] = {
135         { 0xFF, "Default" },
136         { 0, NULL }
137 };
138
139 static const value_string pn_ptcp_clock_class_vals[] = {
140         { 0xFF, "Slave-only clock" },
141         { 0, NULL }
142 };
143
144 static const value_string pn_ptcp_clock_accuracy_vals[] = {
145         { 0x20, "25ns" },
146         { 0x21, "100ns (Default)" },
147         { 0x22, "250ns" },
148         { 0x23, "1us" },
149         { 0x24, "2.5us" },
150         { 0x25, "10us" },
151         { 0x26, "25us" },
152         { 0x27, "100us" },
153         { 0x28, "250us" },
154         { 0x29, "1ms" },
155         { 0xFE, "Unknown" },
156         { 0, NULL }
157 };
158
159 static const value_string pn_ptcp_profinet_subtype_vals[] = {
160         { 0x01, "RTData" },
161         { 0, NULL }
162 };
163
164
165
166
167 static int
168 dissect_PNPTCP_TLVHeader(tvbuff_t *tvb, int offset,
169         packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint16 *type, guint16 *length)
170 {
171     guint16 tl_type;
172     guint16 tl_length;
173
174
175     /* Type */
176     dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_ptcp_tl_type, &tl_type);
177     *type = tl_type >> 9;
178
179     /* Length */
180     offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_ptcp_tl_length, &tl_length);
181     *length = tl_length & 0x1FF;
182
183     return offset;
184 }
185
186
187 static int
188 dissect_PNPTCP_Subdomain(tvbuff_t *tvb, int offset,
189         packet_info *pinfo, proto_tree *tree, proto_item *item, guint16 u16FrameID)
190 {
191     guint8 mac[6];
192     e_uuid_t uuid;
193
194
195     /* MasterSourceAddress */
196     offset = dissect_pn_mac(tvb, offset, pinfo, tree, hf_pn_ptcp_master_source_address, mac);
197
198     /* SubdomainUUID */
199     offset = dissect_pn_uuid(tvb, offset, pinfo, tree, hf_pn_ptcp_subdomain_uuid, &uuid);
200
201     if(u16FrameID == 0xff00 || u16FrameID == 0xff01) {
202        col_append_fstr(pinfo->cinfo, COL_INFO, ", Master=%02x:%02x:%02x:%02x:%02x:%02x",
203             mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
204     }
205
206         proto_item_append_text(item, ": MasterSource=%02x:%02x:%02x:%02x:%02x:%02x",
207         mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
208
209     proto_item_append_text(item, ", Subdomain=%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
210                                       uuid.Data1, uuid.Data2, uuid.Data3,
211                                       uuid.Data4[0], uuid.Data4[1],
212                                       uuid.Data4[2], uuid.Data4[3],
213                                       uuid.Data4[4], uuid.Data4[5],
214                                       uuid.Data4[6], uuid.Data4[7]);
215
216     return offset;
217 }
218
219
220 static int
221 dissect_PNPTCP_Time(tvbuff_t *tvb, int offset,
222         packet_info *pinfo, proto_tree *tree, proto_item *item)
223 {
224     guint16 EpochNumber;
225     guint32 Seconds;
226     guint32 NanoSeconds;
227
228
229     /* EpochNumber */
230     offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_ptcp_epoch_number, &EpochNumber);
231
232     /* Seconds */
233     offset = dissect_pn_uint32(tvb, offset, pinfo, tree, hf_pn_ptcp_seconds, &Seconds);
234
235     /* NanoSeconds */
236     offset = dissect_pn_uint32(tvb, offset, pinfo, tree, hf_pn_ptcp_nanoseconds, &NanoSeconds);
237
238         proto_item_append_text(item, ": Seconds=%u NanoSeconds=%u EpochNumber=%u",
239         Seconds, NanoSeconds, EpochNumber);
240
241     col_append_fstr(pinfo->cinfo, COL_INFO, ", Time: %4us %09uns, Epoch: %u", 
242         Seconds, NanoSeconds, EpochNumber);
243
244     return offset;
245 }
246
247
248 static int
249 dissect_PNPTCP_TimeExtension(tvbuff_t *tvb, int offset,
250         packet_info *pinfo, proto_tree *tree, proto_item *item)
251 {
252     guint16 Flags;
253     guint16 CurrentUTCOffset;
254
255
256     /* Flags */
257     offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_ptcp_flags, &Flags);
258
259     /* CurrentUTCOffset */
260     offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_ptcp_currentutcoffset, &CurrentUTCOffset);
261
262     /* Padding */
263     offset = dissect_pn_align4(tvb, offset, pinfo, tree);
264
265         proto_item_append_text(item, ": Flags=0x%x, CurrentUTCOffset=%u", Flags, CurrentUTCOffset);
266
267     return offset;
268 }
269
270
271 static int
272 dissect_PNPTCP_Master(tvbuff_t *tvb, int offset,
273         packet_info *pinfo, proto_tree *tree, proto_item *item)
274 {
275     guint8 MasterPriority1;
276     guint8 MasterPriority2;
277     guint8 ClockClass;
278     guint8 ClockAccuracy;
279     gint16 ClockVariance;
280
281
282     /* MasterPriority1 */
283     offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_master_priority1, &MasterPriority1);
284
285     /* MasterPriority2 */
286     offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_master_priority2, &MasterPriority2);
287
288     /* ClockClass */
289     offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_clock_class, &ClockClass);
290
291     /* ClockAccuracy */
292     offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_clock_accuracy, &ClockAccuracy);
293
294     /* ClockVariance */
295     offset = dissect_pn_int16(tvb, offset, pinfo, tree, hf_pn_ptcp_clockvariance, &ClockVariance);
296
297     /* Padding */
298     offset = dissect_pn_align4(tvb, offset, pinfo, tree);
299
300     col_append_fstr(pinfo->cinfo, COL_INFO, ", Prio1=\"%s\"",
301         val_to_str(MasterPriority1, pn_ptcp_master_prio1_short_vals, "(Reserved: 0x%x)"));
302
303         proto_item_append_text(item, ": Prio1=\"%s\", Prio2=%s, Clock: Class=\"%s\", Accuracy=%s, Variance=%d",
304         val_to_str(MasterPriority1, pn_ptcp_master_prio1_short_vals, "(Reserved: 0x%x)"), 
305         val_to_str(MasterPriority2, pn_ptcp_master_prio2_vals, "(Reserved: 0x%x)"), 
306         val_to_str(ClockClass, pn_ptcp_clock_class_vals, "(Reserved: 0x%x)"), 
307         val_to_str(ClockAccuracy, pn_ptcp_clock_accuracy_vals, "(Reserved: 0x%x)"), 
308         ClockVariance);
309
310     return offset;
311 }
312
313
314 static int
315 dissect_PNPTCP_PortParameter(tvbuff_t *tvb, int offset,
316         packet_info *pinfo, proto_tree *tree, proto_item *item)
317 {
318     guint32 t2portrxdelay;
319     guint32 t3porttxdelay;
320
321
322     /* Padding */
323     offset = dissect_pn_align4(tvb, offset, pinfo, tree);
324
325     /* T2PortRxDelay */
326     offset = dissect_pn_uint32(tvb, offset, pinfo, tree, hf_pn_ptcp_t2portrxdelay, &t2portrxdelay);
327
328     /* T3PortTxDelay */
329     offset = dissect_pn_uint32(tvb, offset, pinfo, tree, hf_pn_ptcp_t3porttxdelay, &t3porttxdelay);
330
331         proto_item_append_text(item, ": T2PortRxDelay=%uns, T3PortTxDelay=%uns",
332         t2portrxdelay, t3porttxdelay);
333
334     col_append_fstr(pinfo->cinfo, COL_INFO, ", T2Rx=%uns, T3Tx=%uns",
335         t2portrxdelay, t3porttxdelay);
336
337     return offset;
338 }
339
340
341 static int
342 dissect_PNPTCP_DelayParameter(tvbuff_t *tvb, int offset,
343         packet_info *pinfo, proto_tree *tree, proto_item *item)
344 {
345     guint8 mac[6];
346
347
348     /* PortMACAddress */
349     offset = dissect_pn_mac(tvb, offset, pinfo, tree, hf_pn_ptcp_port_mac_address, mac);
350
351     /* Padding */
352     offset = dissect_pn_align4(tvb, offset, pinfo, tree);
353
354
355     proto_item_append_text(item, ": PortMAC=%02x:%02x:%02x:%02x:%02x:%02x",
356         mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
357
358     col_append_fstr(pinfo->cinfo, COL_INFO, ", PortMAC=%02x:%02x:%02x:%02x:%02x:%02x",
359         mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
360
361     return offset;
362 }
363
364
365 static int
366 dissect_PNPTCP_PortTime(tvbuff_t *tvb, int offset,
367         packet_info *pinfo, proto_tree *tree, proto_item *item)
368 {
369     guint32 t2timestamp;
370
371
372     /* Padding */
373     offset = dissect_pn_align4(tvb, offset, pinfo, tree);
374
375         /* T2TimeStamp */
376     offset = dissect_pn_uint32(tvb, offset, pinfo, tree, hf_pn_ptcp_t2timestamp, &t2timestamp);
377
378         proto_item_append_text(item, ": T2TimeStamp=%uns", t2timestamp);
379
380     col_append_fstr(pinfo->cinfo, COL_INFO, ", T2TS=%uns", t2timestamp);
381
382         return offset;
383 }
384
385
386 static int
387 dissect_PNPTCP_Option_PROFINET(tvbuff_t *tvb, int offset,
388         packet_info *pinfo, proto_tree *tree, proto_item *item, guint16 length)
389 {
390     guint8 subType;
391     e_uuid_t uuid;
392
393     /* OUI already dissected! */
394
395     /* SubType */
396     offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_profinet_subtype, &subType);
397     length --;
398
399     switch(subType) {
400     case 1: /* RTData */
401         /* Padding */
402         offset = dissect_pn_align4(tvb, offset, pinfo, tree);
403
404         /* IRDataUUID */
405         offset = dissect_pn_uuid(tvb, offset, pinfo, tree, hf_pn_ptcp_irdata_uuid, &uuid);
406         proto_item_append_text(item, ": IRDataUUID=%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
407                                       uuid.Data1, uuid.Data2, uuid.Data3,
408                                       uuid.Data4[0], uuid.Data4[1],
409                                       uuid.Data4[2], uuid.Data4[3],
410                                       uuid.Data4[4], uuid.Data4[5],
411                                       uuid.Data4[6], uuid.Data4[7]);
412
413         break;
414     default:
415         offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, length);
416         break;
417     }
418
419     return offset;
420 }
421
422
423 static int
424 dissect_PNPTCP_Option(tvbuff_t *tvb, int offset,
425         packet_info *pinfo, proto_tree *tree, proto_item *item, guint16 length)
426 {
427         guint32 oui;
428
429
430     /* verify remaining TLV length */
431         if (length < 4)
432         {
433         if (tree) {
434             /* too short */
435             offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, length);
436         }
437                 return (offset);
438         }
439
440         /* OUI (organizational unique id) */
441     offset = dissect_pn_oid(tvb, offset, pinfo,tree, hf_pn_ptcp_oui, &oui);
442     length -= 3;
443
444         switch (oui)
445         {
446         case OUI_PROFINET:
447         case OUI_PROFINET_MULTICAST:
448         proto_item_append_text(item, ": PROFINET");
449         offset = dissect_PNPTCP_Option_PROFINET(tvb, offset, pinfo, tree, item, length);
450                 break;
451         default:
452         /* SubType */
453         offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, length);
454         }
455
456         return (offset);
457 }
458
459
460 static int
461 dissect_PNPTCP_block(tvbuff_t *tvb, int offset,
462         packet_info *pinfo, proto_tree *tree, proto_item *item _U_, gboolean *end, guint16 u16FrameID)
463 {
464     guint16 type;
465     guint16 length;
466
467         proto_item *sub_item;
468         proto_tree *sub_tree;
469         proto_item *tlvheader_item;
470         proto_tree *tlvheader_tree;
471         guint32 u32SubStart;
472
473
474     *end = FALSE;
475
476     /* block subtree */
477     sub_item = proto_tree_add_item(tree, hf_pn_ptcp_block, tvb, offset, 0, ENC_NA);
478         sub_tree = proto_item_add_subtree(sub_item, ett_pn_ptcp_block);
479     u32SubStart = offset;
480
481     /* tlvheader subtree */
482     tlvheader_item = proto_tree_add_item(sub_tree, hf_pn_ptcp_block_tlvheader, tvb, offset, 2 /* len */, ENC_NA);
483         tlvheader_tree = proto_item_add_subtree(tlvheader_item, ett_pn_ptcp_block_header);
484
485     offset = dissect_PNPTCP_TLVHeader(tvb, offset, pinfo, tlvheader_tree, sub_item, &type, &length);
486
487         proto_item_set_text(sub_item, "%s",
488         val_to_str(type, pn_ptcp_block_type, "Unknown"));
489
490         proto_item_append_text(tlvheader_item, ": Type=%s (%x), Length=%u",
491         val_to_str(type, pn_ptcp_block_type, "Unknown"), type, length);
492
493     switch(type) {
494     case(0x00): /* End, no content */
495         *end = TRUE;
496         break;
497     case(0x01): /* Subdomain */
498         dissect_PNPTCP_Subdomain(tvb, offset, pinfo, sub_tree, sub_item, u16FrameID);
499         break;
500     case(0x02): /* Time */
501         dissect_PNPTCP_Time(tvb, offset, pinfo, sub_tree, sub_item);
502         break;
503     case(0x03): /* TimeExtension */
504         dissect_PNPTCP_TimeExtension(tvb, offset, pinfo, sub_tree, sub_item);
505         break;
506     case(0x04): /* Master */
507         dissect_PNPTCP_Master(tvb, offset, pinfo, sub_tree, sub_item);
508         break;
509     case(0x05): /* PortParameter */
510         dissect_PNPTCP_PortParameter(tvb, offset, pinfo, sub_tree, sub_item);
511         break;
512     case(0x06): /* DelayParameter */
513         dissect_PNPTCP_DelayParameter(tvb, offset, pinfo, sub_tree, sub_item);
514         break;
515     case(0x07): /* PortTime */
516         dissect_PNPTCP_PortTime(tvb, offset, pinfo, sub_tree, sub_item);
517         break;
518     case(0x7F): /* Organizational Specific */
519         dissect_PNPTCP_Option(tvb, offset, pinfo, sub_tree, sub_item, length);
520         break;
521     default:
522         offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, length);
523     }
524     offset += length;
525
526         proto_item_set_len(sub_item, offset - u32SubStart);
527
528     return offset;
529 }
530
531
532 static int
533 dissect_PNPTCP_blocks(tvbuff_t *tvb, int offset,
534         packet_info *pinfo, proto_tree *tree, proto_item *item, guint16 u16FrameID)
535 {
536     gboolean end = FALSE;
537
538     /* as long as we have some bytes, try a new block */
539     while(!end) {
540         offset = dissect_PNPTCP_block(tvb, offset, pinfo, tree, item, &end, u16FrameID);
541     }
542
543     return offset;
544 }
545
546
547 static int
548 dissect_PNPTCP_FollowUpPDU(tvbuff_t *tvb, int offset,
549         packet_info *pinfo, proto_tree *tree, proto_item *item, guint16 u16FrameID, const char *name, const char *name_short)
550 {
551         proto_item *header_item;
552         proto_tree *header_tree;
553     guint16 seq_id;
554     gint32 delay1ns_fup;
555
556
557     /* dissect the header */
558     header_item = proto_tree_add_item(tree, hf_pn_ptcp_header, tvb, offset, 20 /* len */, ENC_NA);
559         header_tree = proto_item_add_subtree(header_item, ett_pn_ptcp_header);
560
561     /* Padding 12 bytes */
562     offset = dissect_pn_padding(tvb, offset, pinfo, header_tree, 12);
563
564     /* SequenceID */
565     offset = dissect_pn_uint16(tvb, offset, pinfo, header_tree, hf_pn_ptcp_seq_id, &seq_id);
566
567     /* Padding */
568     offset = dissect_pn_align4(tvb, offset, pinfo, header_tree);
569
570     /* Delay1ns_FUP */
571     offset = dissect_pn_int32(tvb, offset, pinfo, header_tree, hf_pn_ptcp_delay1ns_fup, &delay1ns_fup);
572
573     col_append_fstr(pinfo->cinfo, COL_INFO, "%s, Seq=%3u, Delay=%11dns", name, seq_id, delay1ns_fup);
574     proto_item_append_text(item, "%s: Sequence=%u, Delay=%dns", name_short, seq_id, delay1ns_fup);
575     proto_item_append_text(header_item, ": Sequence=%u, Delay=%dns", seq_id, delay1ns_fup);
576
577
578     /* dissect the TLV blocks */
579     offset = dissect_PNPTCP_blocks(tvb, offset, pinfo, tree, item, u16FrameID);
580
581     return offset;
582 }
583
584
585 static int
586 dissect_PNPTCP_RTSyncPDU(tvbuff_t *tvb, int offset,
587         packet_info *pinfo, proto_tree *tree, proto_item *item, guint16 u16FrameID, const char *name, const char *name_short)
588 {
589         proto_item *header_item;
590         proto_tree *header_tree;
591     guint32 res_1;
592     guint32 res_2;
593     guint32 delay10ns;
594     guint16 seq_id;
595     guint8 delay1ns_8;
596     guint64 delay1ns_64;
597     guint32 delay1ns_32;
598     guint32 delayms;
599
600
601     header_item = proto_tree_add_item(tree, hf_pn_ptcp_header, tvb, offset, 20 /* len */, ENC_NA);
602         header_tree = proto_item_add_subtree(header_item, ett_pn_ptcp_header);
603
604     /* Reserved_1 */
605     offset = dissect_pn_uint32(tvb, offset, pinfo, header_tree, hf_pn_ptcp_res1, &res_1);
606
607     /* Reserved_2 */
608     offset = dissect_pn_uint32(tvb, offset, pinfo, header_tree, hf_pn_ptcp_res2, &res_2);
609
610     /* Delay10ns */
611     offset = dissect_pn_uint32(tvb, offset, pinfo, header_tree, hf_pn_ptcp_delay10ns, &delay10ns);
612
613     /* SequenceID */
614     offset = dissect_pn_uint16(tvb, offset, pinfo, header_tree, hf_pn_ptcp_seq_id, &seq_id);
615
616     /* Delay1ns */
617     offset = dissect_pn_uint8(tvb, offset, pinfo, header_tree, hf_pn_ptcp_delay1ns_byte, &delay1ns_8);
618
619     /* Padding */
620     offset = dissect_pn_align4(tvb, offset, pinfo, header_tree);
621
622     /* Delay1ns */
623     offset = dissect_pn_uint32(tvb, offset, pinfo, header_tree, hf_pn_ptcp_delay1ns, &delay1ns_32);
624
625     /* Padding */
626     offset = dissect_pn_align4(tvb, offset, pinfo, tree);
627
628
629     delay1ns_64 = ((guint64) delay10ns) * 10 + delay1ns_8 + delay1ns_32;
630     delayms = (guint32) (delay1ns_64 / (1000 * 1000));
631
632     col_append_fstr(pinfo->cinfo, COL_INFO, "%s, Seq=%3u, Delay=%11" G_GINT64_MODIFIER "uns",
633             name, seq_id, delay1ns_64);
634     proto_item_append_text(item, "%s: Sequence=%u, Delay=%" G_GINT64_MODIFIER "uns", 
635         name_short, seq_id, delay1ns_64);
636     proto_item_append_text(header_item, ": Sequence=%u, Delay=%" G_GINT64_MODIFIER "uns", 
637         seq_id, delay1ns_64);
638
639     if(delay1ns_64 != 0)
640         proto_item_append_text(header_item, " (%u.%03u,%03u,%03u sec)",
641             delayms / 1000,
642             delayms % 1000,
643             (delay10ns % (1000*100)) / 100,
644              delay10ns % 100 * 10 + delay1ns_8);
645
646     /* dissect the PDU */
647     offset = dissect_PNPTCP_blocks(tvb, offset, pinfo, tree, item, u16FrameID);
648
649     return offset;
650 }
651
652
653 static int
654 dissect_PNPTCP_AnnouncePDU(tvbuff_t *tvb, int offset,
655         packet_info *pinfo, proto_tree *tree, proto_item *item, guint16 u16FrameID, const char *name, const char *name_short)
656 {
657         proto_item *header_item;
658         proto_tree *header_tree;
659     guint16 seq_id;
660
661
662     /* dissect the header */
663     header_item = proto_tree_add_item(tree, hf_pn_ptcp_header, tvb, offset, 20 /* len */, ENC_NA);
664         header_tree = proto_item_add_subtree(header_item, ett_pn_ptcp_header);
665
666     /* Padding 12 bytes */
667     offset = dissect_pn_padding(tvb, offset, pinfo, header_tree, 12);
668
669     /* SequenceID */
670     offset = dissect_pn_uint16(tvb, offset, pinfo, header_tree, hf_pn_ptcp_seq_id, &seq_id);
671
672     /* Padding 6 bytes */
673     offset = dissect_pn_padding(tvb, offset, pinfo, header_tree, 6);
674
675     col_append_fstr(pinfo->cinfo, COL_INFO, "%s, Seq=%3u", name, seq_id);
676     proto_item_append_text(item, "%s: Sequence=%u", name_short, seq_id);
677     proto_item_append_text(header_item, ": Sequence=%u", seq_id);
678
679
680     /* dissect the PDU */
681     offset = dissect_PNPTCP_blocks(tvb, offset, pinfo, tree, item, u16FrameID);
682
683     return offset;
684 }
685
686
687 static int
688 dissect_PNPTCP_DelayPDU(tvbuff_t *tvb, int offset,
689         packet_info *pinfo, proto_tree *tree, proto_item *item, guint16 u16FrameID, const char *name, const char *name_short)
690 {
691         proto_item *header_item;
692         proto_tree *header_tree;
693     guint16 seq_id;
694     guint32 delay1ns;
695
696
697     /* dissect the header */
698     header_item = proto_tree_add_item(tree, hf_pn_ptcp_header, tvb, offset, 20 /* len */, ENC_NA);
699         header_tree = proto_item_add_subtree(header_item, ett_pn_ptcp_header);
700
701     /* Padding 12 bytes */
702     offset = dissect_pn_padding(tvb, offset, pinfo, header_tree, 12);
703
704     /* SequenceID */
705     offset = dissect_pn_uint16(tvb, offset, pinfo, header_tree, hf_pn_ptcp_seq_id, &seq_id);
706
707     /* Padding */
708     offset = dissect_pn_align4(tvb, offset, pinfo, header_tree);
709
710     /* Delay1ns_FUP */
711     offset = dissect_pn_uint32(tvb, offset, pinfo, header_tree, hf_pn_ptcp_delay1ns, &delay1ns);
712
713     col_append_fstr(pinfo->cinfo, COL_INFO, "%s, Seq=%3u, Delay=%11uns", name, seq_id, delay1ns);
714     proto_item_append_text(item, "%s: Sequence=%u, Delay=%uns", name_short, seq_id, delay1ns);
715     proto_item_append_text(header_item, ": Sequence=%u, Delay=%uns", seq_id, delay1ns);
716
717
718     /* dissect the PDU */
719     offset = dissect_PNPTCP_blocks(tvb, offset, pinfo, tree, item, u16FrameID);
720
721     return offset;
722 }
723
724
725 /* possibly dissect a PN-RT packet (frame ID must be in the appropriate range) */
726 static gboolean
727 dissect_PNPTCP_Data_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
728     void *data _U_)
729 {
730     guint16 u16FrameID;
731     proto_item *item = NULL;
732     proto_tree *ptcp_tree = NULL;
733     int offset = 0;
734         guint32 u32SubStart;
735     /*proto_item *unknown_item = NULL;*/
736
737
738     /* the tvb will NOT contain the frame_id here, so get it from our private data! */
739     u16FrameID = GPOINTER_TO_UINT(pinfo->private_data);
740
741         /* frame id must be in valid range (acyclic Real-Time, PTCP) */
742     /* 0x0000 - 0x007F: RTSyncPDU (with follow up) */
743     /* 0x0080 - 0x00FF: RTSyncPDU (without follow up) */
744     /* 0xFF00 - 0xFF1F: AnnouncePDU */
745     /* 0xFF20 - 0xFF3F: FollowUpPDU */
746     /* 0xFF40 - 0xFF5F: Delay...PDU */
747         if ( (u16FrameID >= 0x0100 && u16FrameID < 0xFF00) || (u16FrameID > 0xFF5F) ) {
748         /* we are not interested in this packet */
749         return FALSE;
750     }
751
752     col_set_str(pinfo->cinfo, COL_PROTOCOL, "PN-PTCP");
753     col_clear(pinfo->cinfo, COL_INFO);
754
755     /* subtree for PTCP */
756         item = proto_tree_add_protocol_format(tree, proto_pn_ptcp, tvb, 0, 0, "PROFINET PTCP, ");
757         ptcp_tree = proto_item_add_subtree(item, ett_pn_ptcp);
758     u32SubStart = offset;
759
760     switch(u16FrameID) {
761     /* range 1 (0x0000 - 0x007F) */
762         /* 0x0000 - 0x001F reserved */
763     case(0x0020):
764         offset = dissect_PNPTCP_RTSyncPDU   (tvb, offset, pinfo, ptcp_tree, item, u16FrameID, "RTSync FU (Clock)", "RTSync FU (Clock)");
765         break;
766     case(0x0021):
767         offset = dissect_PNPTCP_RTSyncPDU   (tvb, offset, pinfo, ptcp_tree, item, u16FrameID, "RTSync FU  (Time)", "RTSync FU (Time)");
768         break;
769         /* 0x0022 - 0x007F reserved */
770
771     /* range 2 (0x0080 - 0x00FF) */
772     case(0x0080):
773         offset = dissect_PNPTCP_RTSyncPDU   (tvb, offset, pinfo, ptcp_tree, item, u16FrameID, "RTSync    (Clock)", "RTSync (Clock)");
774         break;
775     case(0x0081):
776         offset = dissect_PNPTCP_RTSyncPDU   (tvb, offset, pinfo, ptcp_tree, item, u16FrameID, "RTSync     (Time)", "RTSync (Time)");
777         break;
778         /* 0x0081 - 0x00FF reserved */
779
780     /* range 7 (0xFF00 - 0xFF5F) */
781     case(0xff00):
782         offset = dissect_PNPTCP_AnnouncePDU (tvb, offset, pinfo, ptcp_tree, item, u16FrameID, "Announce  (Clock)", "Announce (Clock)");
783         break;
784     case(0xff01):
785         offset = dissect_PNPTCP_AnnouncePDU (tvb, offset, pinfo, ptcp_tree, item, u16FrameID, "Announce   (Time)", "Announce (Time)");
786         break;
787         /* 0xFF02 - 0xFF1F reserved */
788     case(0xff20):
789         offset = dissect_PNPTCP_FollowUpPDU (tvb, offset, pinfo, ptcp_tree, item, u16FrameID, "FollowUp  (Clock)", "FollowUp (Clock)");
790         break;
791     case(0xff21):
792         offset = dissect_PNPTCP_FollowUpPDU (tvb, offset, pinfo, ptcp_tree, item, u16FrameID, "FollowUp   (Time)", "FollowUp (Time)");
793         break;
794         /* 0xFF22 - 0xFF3F reserved */
795     case(0xff40):
796         offset = dissect_PNPTCP_DelayPDU    (tvb, offset, pinfo, ptcp_tree, item, u16FrameID, "DelayReq         ", "DelayReq");
797         break;
798     case(0xff41):
799         offset = dissect_PNPTCP_DelayPDU    (tvb, offset, pinfo, ptcp_tree, item, u16FrameID, "DelayRes         ", "DelayRes");
800         break;
801     case(0xff42):
802         offset = dissect_PNPTCP_DelayPDU    (tvb, offset, pinfo, ptcp_tree, item, u16FrameID, "DelayFuRes       ", "DelayFuRes");
803         break;
804     case(0xff43):
805         offset = dissect_PNPTCP_DelayPDU    (tvb, offset, pinfo, ptcp_tree, item, u16FrameID, "DelayRes         ", "DelayRes");
806         break;
807         /* 0xFF44 - 0xFF5F reserved */
808     default:
809         offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, tvb_length_remaining(tvb, offset));
810
811         col_append_fstr(pinfo->cinfo, COL_INFO, "Reserved FrameID 0x%04x", u16FrameID);
812
813         proto_item_append_text(item, "Reserved FrameID 0x%04x", u16FrameID);
814
815         offset += tvb_length_remaining(tvb, offset);
816     }
817
818         proto_item_set_len(item, offset - u32SubStart);
819
820     return TRUE;
821 }
822
823
824 void
825 proto_register_pn_ptcp (void)
826 {
827         static hf_register_info hf[] = {
828         { &hf_pn_ptcp_header,
829         { "Header", "pn_ptcp.header", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
830         { &hf_pn_ptcp_block,
831         { "Block", "pn_ptcp.block", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
832         { &hf_pn_ptcp_block_tlvheader,
833         { "TLVHeader", "pn_ptcp.tlvheader", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
834
835         { &hf_pn_ptcp_res1,
836                 { "Reserved 1", "pn_ptcp.res1", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
837         { &hf_pn_ptcp_res2,
838                 { "Reserved 2", "pn_ptcp.res2", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
839         { &hf_pn_ptcp_delay10ns,
840                 { "Delay10ns", "pn_ptcp.delay10ns", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
841         { &hf_pn_ptcp_seq_id,
842                 { "SequenceID", "pn_ptcp.sequence_id", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
843         { &hf_pn_ptcp_delay1ns_byte,
844                 { "Delay1ns_Byte", "pn_ptcp.delay1ns_byte", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
845         { &hf_pn_ptcp_delay1ns,
846                 { "Delay1ns", "pn_ptcp.delay1ns", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
847         { &hf_pn_ptcp_delay1ns_fup,
848                 { "Delay1ns_FUP", "pn_ptcp.delay1ns_fup", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
849
850         { &hf_pn_ptcp_tl_length,
851         { "TypeLength.Length", "pn_ptcp.tl_length", FT_UINT16, BASE_DEC, 0x0, 0x1FF, NULL, HFILL }},
852         { &hf_pn_ptcp_tl_type,
853         { "TypeLength.Type", "pn_ptcp.tl_type", FT_UINT16, BASE_DEC, 0x0, 0xFE00, NULL, HFILL }},
854
855         { &hf_pn_ptcp_master_source_address,
856         { "MasterSourceAddress", "pn_ptcp.master_source_address", FT_ETHER, BASE_NONE, 0x0, 0x0, NULL, HFILL }},
857         { &hf_pn_ptcp_subdomain_uuid,
858         { "SubdomainUUID", "pn_ptcp.subdomain_uuid", FT_GUID, BASE_NONE, 0x0, 0x0, NULL, HFILL }},
859
860     { &hf_pn_ptcp_port_mac_address,
861         { "PortMACAddress", "pn_ptcp.port_mac_address", FT_ETHER, BASE_NONE, 0x0, 0x0, NULL, HFILL }},
862
863         { &hf_pn_ptcp_t2portrxdelay,
864         { "T2PortRxDelay (ns)", "pn_ptcp.t2portrxdelay", FT_UINT32, BASE_DEC, 0x0, 0x0, NULL, HFILL }},
865         { &hf_pn_ptcp_t3porttxdelay,
866         { "T3PortTxDelay (ns)", "pn_ptcp.t3porttxdelay", FT_UINT32, BASE_DEC, 0x0, 0x0, NULL, HFILL }},
867         { &hf_pn_ptcp_t2timestamp,
868         { "T2TimeStamp (ns)", "pn_ptcp.t2timestamp", FT_UINT32, BASE_DEC, 0x0, 0x0, NULL, HFILL }},
869
870         { &hf_pn_ptcp_epoch_number,
871         { "EpochNumber", "pn_ptcp.epoch_number", FT_UINT16, BASE_DEC, 0x0, 0x0, NULL, HFILL }},
872         { &hf_pn_ptcp_seconds,
873         { "Seconds", "pn_ptcp.seconds", FT_UINT32, BASE_DEC, 0x0, 0x0, NULL, HFILL }},
874         { &hf_pn_ptcp_nanoseconds,
875         { "NanoSeconds", "pn_ptcp.nanoseconds", FT_UINT32, BASE_DEC, 0x0, 0x0, NULL, HFILL }},
876
877         { &hf_pn_ptcp_flags,
878         { "Flags", "pn_ptcp.flags", FT_UINT16, BASE_HEX, 0x0, 0x0, NULL, HFILL }},
879         { &hf_pn_ptcp_currentutcoffset,
880         { "CurrentUTCOffset", "pn_ptcp.currentutcoffset", FT_UINT16, BASE_DEC, 0x0, 0x0, NULL, HFILL }},
881
882         { &hf_pn_ptcp_master_priority1,
883         { "MasterPriority1", "pn_ptcp.master_priority1", FT_UINT8, BASE_DEC, VALS(pn_ptcp_master_prio1_vals), 0x0, NULL, HFILL }},
884         { &hf_pn_ptcp_master_priority2,
885         { "MasterPriority2", "pn_ptcp.master_priority2", FT_UINT8, BASE_DEC, VALS(pn_ptcp_master_prio2_vals), 0x0, NULL, HFILL }},
886         { &hf_pn_ptcp_clock_class,
887         { "ClockClass", "pn_ptcp.clock_class", FT_UINT8, BASE_DEC, VALS(pn_ptcp_clock_class_vals), 0x0, NULL, HFILL }},
888         { &hf_pn_ptcp_clock_accuracy,
889         { "ClockAccuracy", "pn_ptcp.clock_accuracy", FT_UINT8, BASE_DEC, VALS(pn_ptcp_clock_accuracy_vals), 0x0, NULL, HFILL }},
890         { &hf_pn_ptcp_clockvariance,
891         { "ClockVariance", "pn_ptcp.clockvariance", FT_INT16, BASE_DEC, 0x0, 0x0, NULL, HFILL }},
892
893         { &hf_pn_ptcp_oui,
894                 { "Organizationally Unique Identifier", "pn_ptcp.oui", FT_UINT24, BASE_HEX,
895                 VALS(pn_ptcp_oui_vals), 0x0, NULL, HFILL }},
896         { &hf_pn_ptcp_profinet_subtype,
897                 { "Subtype",    "pn_ptcp.subtype", FT_UINT8, BASE_HEX,
898                 VALS(pn_ptcp_profinet_subtype_vals), 0x0, "PROFINET Subtype", HFILL }},
899
900         { &hf_pn_ptcp_irdata_uuid,
901         { "IRDataUUID", "pn_ptcp.irdata_uuid", FT_GUID, BASE_NONE, 0x0, 0x0, NULL, HFILL }},
902         };
903
904         static gint *ett[] = {
905                 &ett_pn_ptcp,
906                 &ett_pn_ptcp_header,
907         &ett_pn_ptcp_block,
908         &ett_pn_ptcp_block_header
909     };
910         proto_pn_ptcp = proto_register_protocol ("PROFINET PTCP", "PN-PTCP", "pn_ptcp");
911         proto_register_field_array (proto_pn_ptcp, hf, array_length (hf));
912         proto_register_subtree_array (ett, array_length (ett));
913 }
914
915 void
916 proto_reg_handoff_pn_ptcp (void)
917 {
918     /* register ourself as an heuristic pn-rt payload dissector */
919         heur_dissector_add("pn_rt", dissect_PNPTCP_Data_heur, proto_pn_ptcp);
920 }