checkAPIs.pl: support for new-style dissectors in check_hf_entries
[metze/wireshark/wip.git] / epan / dissectors / packet-metamako.c
1 /* packet-metamako.c
2  * Routines for dissection of Metamako trailers. Forked from
3  * packet-vssmonitoring.c on 20th December, 2015.
4  * See https://www.metamako.com for further details.
5  *
6  * Copyright VSS-Monitoring 2011
7  * Copyright Metamako LP 2015
8  *
9  * 20111205 - First edition by Sake Blok (sake.blok@SYN-bit.nl)
10  * 20151220 - Forked to become packet-metamako.c
11  *
12  * Wireshark - Network traffic analyzer
13  * By Gerald Combs <gerald@wireshark.org>
14  * Copyright 1998 Gerald Combs
15  *
16  * SPDX-License-Identifier: GPL-2.0-or-later
17  */
18
19 #include "config.h"
20
21 #include <epan/packet.h>
22
23 #include <glib.h>
24 #include <glib/gprintf.h>
25
26 void proto_register_metamako(void);
27 void proto_reg_handoff_metamako(void);
28
29 static int proto_metamako = -1;
30
31 static int hf_metamako_origfcs = -1;
32 static int hf_metamako_trailerext = -1;
33 static int hf_metamako_unknownext = -1;
34 static int hf_metamako_seqnum = -1;
35 static int hf_metamako_tagstring = -1;
36 static int hf_metamako_fracns = -1;
37 static int hf_metamako_time = -1;
38 static int hf_metamako_flags = -1;
39 static int hf_metamako_srcport = -1;
40 static int hf_metamako_srcdevice = -1;
41 static int hf_metamako_tdiff = -1;
42
43 static int hf_metamako_flags_orig_fcs_vld = -1;
44 static int hf_metamako_flags_has_ext = -1;
45 static int hf_metamako_reserved = -1;
46
47 static gint ett_metamako = -1;
48 static gint ett_metamako_timestamp = -1;
49 static gint ett_metamako_extensions = -1;
50 static gint ett_metamako_flags = -1;
51
52 static const int * flags[] = {
53   &hf_metamako_flags_orig_fcs_vld,
54   &hf_metamako_flags_has_ext,
55   &hf_metamako_reserved,
56   NULL
57 };
58
59 static void
60 sub_nanos_base_custom(gchar *result, guint32 value)
61 {
62   double temp_double;
63   temp_double = ((double)value) / (1U << 24);
64   g_snprintf(result, ITEM_LABEL_LENGTH, "%1.9fns", temp_double);
65 }
66
67 static int
68 validate_metamako_timestamp(nstime_t *metamako_time, packet_info *pinfo)
69 {
70   if ( metamako_time->secs > 3600 && metamako_time->nsecs < 1000000000 ) {
71     if ( metamako_time->secs > pinfo->fd->abs_ts.secs ) {
72       if ( metamako_time->secs - pinfo->fd->abs_ts.secs > 2592000 ) /* 30 days */
73         return 0;
74     } else {
75       if ( pinfo->fd->abs_ts.secs - metamako_time->secs > 2592000 ) /* 30 days */
76         return 0;
77     }
78   }
79   else {
80     return 0;
81   }
82   return 1;
83 }
84
85 static int
86 dissect_metamako(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
87 {
88   guint           i, j;
89
90   proto_tree    *ti, *parent, *item;
91   proto_tree    *metamako_tree, *timestamp_tree;
92   proto_tree    *extensions_tree;
93
94   guint         offset = 0;
95
96   guint         captured_trailer_bytes;
97   guint         metamako_trailer_bytes;
98   guint         trailer_valid;
99
100   nstime_t      metamako_time, timediff;
101   guint         metamako_meta;
102   guint         metamako_tlv_present;
103
104   guint         metamako_tlv_count;
105   guint         metamako_tlv_firstword;
106   guint         metamako_tlv_len;
107   guint         metamako_tlv_tag;
108   guint         metamako_tlv_pos;
109   guint         metamako_tlv_bytes;
110
111   guint8        metamako_srcport;
112   guint16       metamako_srcdevice;
113   guint8        metamako_flags;
114
115   struct tm     *tmp;
116
117   /* The Metamako trailer is made up of:
118      4 bytes -- original FCS
119      N bytes -- trailer extensions
120      4 bytes -- seconds
121      4 bytes -- nanoseconds
122      1 byte  -- flags
123      2 bytes -- device ID
124      1 byte  -- port ID
125      4 bytes -- New (valid) FCS (may or may not have been captured)
126   */
127
128   /* First get the captured length of the trailer */
129   captured_trailer_bytes = tvb_captured_length(tvb);
130
131   /* If we have less than 12 bytes captured, we can't
132      read the timestamp to confirm the heuristic */
133   if ( captured_trailer_bytes < 12 )
134     return 0;
135
136   /* Init variables before loop */
137   metamako_trailer_bytes = captured_trailer_bytes;
138   metamako_tlv_count = 0;
139   metamako_tlv_bytes = 0;
140   metamako_tlv_present = 0;
141
142   /* Default state is no valid trailer found */
143   trailer_valid = 0;
144
145   /* Loop through the trailer bytes, try to find a valid trailer.
146    * Only try twice:
147    *   - First try the case there there IS NO trailing FCS
148    *   - Second try the case where where IS a trailing FCS
149    */
150   for ( i = 0; i < 2 && metamako_trailer_bytes >= 12 && !trailer_valid; i++ ) {
151     /* Start at the tail of the trailer and work inwards */
152     metamako_meta       = tvb_get_ntohl(tvb, metamako_trailer_bytes - 4);
153     metamako_flags      = (metamako_meta >> 24) & 0xFF;
154     metamako_trailer_bytes -= 4;
155     metamako_time.nsecs = tvb_get_ntohl(tvb, metamako_trailer_bytes - 4);
156     metamako_trailer_bytes -= 4;
157     metamako_time.secs  = tvb_get_ntohl(tvb, metamako_trailer_bytes - 4);
158     metamako_trailer_bytes -= 4;
159
160     /* Check the validity of the candidate timestamp */
161     if ( validate_metamako_timestamp(&metamako_time, pinfo) ) {
162       /* Check if the trailer has tlv extensions */
163       metamako_tlv_present = metamako_flags & 0x2;
164       metamako_tlv_bytes = 0;
165       metamako_tlv_count = 0;
166       if ( metamako_tlv_present ) {
167         /* Extensions are flagged as included, check if there is bytes
168          * to support this, and try to decode.
169          */
170         while ( metamako_trailer_bytes >= 4 ) {
171           /* Bytes are here, decode as TLVs */
172           metamako_tlv_firstword = tvb_get_ntohl(tvb, metamako_trailer_bytes - 4);
173           metamako_tlv_count++;
174           metamako_tlv_bytes += 4;
175           metamako_trailer_bytes -= 4;
176
177           /* Extract length */
178           metamako_tlv_len = (metamako_tlv_firstword >> 6) & 0x3;
179
180           /* If its a secondary tag header, extract the extended length */
181           if ( ( metamako_tlv_firstword & 0x1F ) == 0x1F )
182             metamako_tlv_len = ( (metamako_tlv_firstword >> 6) & 0x3FF ) + 1;
183
184           /* Skip over the data, find the next tag */
185           while ( metamako_tlv_len > 0 ) {
186             metamako_tlv_len--;
187             metamako_tlv_bytes += 4;
188             metamako_trailer_bytes -= 4;
189           }
190
191           /* If this is flagged as the last TLV, stop */
192           if ( ( metamako_tlv_firstword >> 5 ) & 0x1 ) {
193             break;
194           }
195         }
196       }
197
198       /* There should be at least enough bytes for the Orig FCS left
199        * any bytes before this are padding
200        */
201       if ( metamako_trailer_bytes >= 4 ) {
202         /* Decrement by the number of bytes in the Orig FCS field */
203         metamako_trailer_bytes -= 4;
204
205         /* This byte offset is the beginning of the Metamako trailer */
206         offset = metamako_trailer_bytes;
207
208         /* If we've made it this far, it appears we've got a valid trailer */
209         trailer_valid = 1;
210       }
211     }
212
213     /* If we didn't find a valid metamako trailer, try again using 4 bytes less */
214     if ( !trailer_valid ) {
215       captured_trailer_bytes -= 4;
216       metamako_trailer_bytes = captured_trailer_bytes;
217     }
218   }
219
220   /* Did we find a valid trailer? */
221   if ( !trailer_valid )
222     return 0;
223
224   /* Everything looks good! Now dissect the trailer. */
225   ti = proto_tree_add_item(tree, proto_metamako, tvb, offset, (captured_trailer_bytes - offset), ENC_NA);
226   metamako_tree = proto_item_add_subtree(ti, ett_metamako);
227
228   /* Original FCS */
229   proto_tree_add_item(metamako_tree, hf_metamako_origfcs, tvb, offset, 4, ENC_BIG_ENDIAN);
230   offset += 4;
231
232   /* TLV Extensions */
233   if ( metamako_tlv_present ) {
234     parent = proto_tree_add_item(metamako_tree, hf_metamako_trailerext, tvb, captured_trailer_bytes - 12 - metamako_tlv_bytes, metamako_tlv_bytes, ENC_NA);
235     extensions_tree = proto_item_add_subtree(parent, ett_metamako_extensions);
236     while ( metamako_tlv_count > 0 ) {
237       metamako_tlv_pos = captured_trailer_bytes - 16;
238       i = metamako_tlv_count;
239       do {
240         /* Read TLV word and decode */
241         metamako_tlv_firstword = tvb_get_ntohl(tvb, metamako_tlv_pos);
242         metamako_tlv_len       = ( metamako_tlv_firstword >> 6 ) & 0x3;
243         metamako_tlv_bytes     = ( metamako_tlv_len * 4 ) + 3;
244         metamako_tlv_tag       = ( metamako_tlv_firstword & 0x1F );
245
246         /* If this is a Secondary Tag Header, decode the tag extensions */
247         if ( ( metamako_tlv_firstword & 0x1F ) == 0x1F ) {
248           metamako_tlv_len   =  ( ( metamako_tlv_firstword >> 6 ) & 0x3FF ) + 1;
249           metamako_tlv_bytes =  ( metamako_tlv_len * 4 );
250           metamako_tlv_tag   += ( ( metamako_tlv_firstword >> 16 ) & 0xFFFF );
251         }
252
253         /* Decrement TLV count */
254         i--;
255
256         /* Skip over the data if this is not our destination */
257         if ( i != 0 )
258           metamako_tlv_pos -= ( metamako_tlv_len + 1 ) * 4;
259       }
260       while ( i > 0 );
261
262       /* We've skipped to the i-th TLV, decode it */
263       switch ( metamako_tlv_tag ) {
264         case 0:
265           /* Sequence Number */
266           metamako_tlv_pos -= ( metamako_tlv_len + 1 ) * 4;
267           proto_tree_add_item(extensions_tree, hf_metamako_seqnum, tvb, metamako_tlv_pos + 5, 2, ENC_BIG_ENDIAN);
268           proto_item_append_text(parent, ", Sequence No: %d", tvb_get_ntohs(tvb, metamako_tlv_pos + 5));
269           /* Increment the offset by the Data + Tag size */
270           offset += ( metamako_tlv_len + 1 ) * 4;
271           break;
272
273         case 1:
274           /* Sub-nanoseconds */
275           metamako_tlv_pos -= ( metamako_tlv_len + 1 ) * 4;
276           proto_tree_add_item(extensions_tree, hf_metamako_fracns, tvb, metamako_tlv_pos + 4, 3, ENC_BIG_ENDIAN);
277           proto_item_append_text(parent, ", Sub-nanoseconds: %1.9fns", ((double)(tvb_get_ntohl(tvb, metamako_tlv_pos + 3) & 0x00FFFFFF)) / (1U << 24));
278           /* Increment the offset by the Data + Tag size */
279           offset += ( metamako_tlv_len + 1 ) * 4;
280           break;
281
282         case 31:
283           /* Tag String */
284           metamako_tlv_pos -= ( metamako_tlv_len + 1 ) * 4;
285           proto_tree_add_item(extensions_tree, hf_metamako_tagstring, tvb, metamako_tlv_pos + 4, metamako_tlv_len * 4, ENC_ASCII|ENC_NA);
286           /* Increment the offset by the Data + Tag size */
287           offset += ( metamako_tlv_len + 1 ) * 4;
288           break;
289
290         default:
291           /* Unknown tag: just print it's ID and Data */
292           metamako_tlv_pos -= ( metamako_tlv_len + 1 ) * 4;
293           item = proto_tree_add_item(extensions_tree, hf_metamako_unknownext, tvb, metamako_tlv_pos + 4, metamako_tlv_bytes, ENC_NA);
294           /* Start with the Tag */
295           proto_item_set_text(item, "Unknown Tag [0x%05x]: ", metamako_tlv_tag);
296           /* Iterate through the data appending as we go */
297           for ( j = 0; j < metamako_tlv_bytes; j++ ) {
298             proto_item_append_text(item, "%02x", tvb_get_guint8(tvb, metamako_tlv_pos + 4 + j));
299             if ( (28 + j*2) >= ITEM_LABEL_LENGTH ) {
300               proto_item_append_text(item, "...");
301               break;
302             }
303           }
304           /* Increment the offset by the Data + Tag size */
305           offset += ( metamako_tlv_len + 1 ) * 4;
306           break;
307       }
308
309       /* Decrement count as we've just decoded a TLV */
310       metamako_tlv_count--;
311     }
312   }
313
314   /* Timestamp */
315   item = proto_tree_add_time(metamako_tree, hf_metamako_time, tvb, offset, 8, &metamako_time);
316   timestamp_tree = proto_item_add_subtree(item, ett_metamako_timestamp);
317
318   tmp = localtime(&metamako_time.secs);
319   if (tmp)
320     proto_item_append_text(ti, ", Timestamp: %02d:%02d:%02d.%09ld",
321                              tmp->tm_hour, tmp->tm_min, tmp->tm_sec,(long)metamako_time.nsecs);
322   else
323     proto_item_append_text(ti, ", Timestamp: <Not representable>");
324
325   /* [Timestamp difference from pcap time] */
326   nstime_delta(&timediff, &metamako_time, &pinfo->fd->abs_ts);
327   item = proto_tree_add_time(timestamp_tree, hf_metamako_tdiff, tvb, offset, 8, &timediff);
328   PROTO_ITEM_SET_GENERATED(item);
329
330   offset += 8;
331
332   /* Flags */
333   proto_tree_add_bitmask(metamako_tree, tvb, offset, hf_metamako_flags, ett_metamako_flags, flags, ENC_BIG_ENDIAN);
334   offset++;
335
336   /* Source device */
337   metamako_srcdevice = tvb_get_ntohs(tvb, offset);
338   proto_tree_add_item(metamako_tree, hf_metamako_srcdevice, tvb, offset, 2, ENC_BIG_ENDIAN);
339   proto_item_append_text(ti, ", Source Device: %d", metamako_srcdevice);
340   offset += 2;
341
342   /* Source port */
343   metamako_srcport = tvb_get_guint8(tvb, offset);
344   proto_tree_add_item(metamako_tree, hf_metamako_srcport, tvb, offset, 1, ENC_BIG_ENDIAN);
345   proto_item_append_text(ti, ", Source Port: %d", metamako_srcport);
346   offset++;
347
348   return offset;
349 }
350
351 void
352 proto_register_metamako(void)
353 {
354   static hf_register_info hf[] = {
355     { &hf_metamako_origfcs, {
356         "Original FCS", "metamako.orig_fcs",
357         FT_UINT32, BASE_HEX, NULL, 0x0,
358         NULL, HFILL }},
359
360     { &hf_metamako_trailerext, {
361         "Trailer Extensions", "metamako.ext",
362         FT_NONE, BASE_NONE, NULL, 0x0,
363         NULL, HFILL }},
364
365     { &hf_metamako_unknownext, {
366         "Unknown Tag", "metamako.unknown",
367         FT_BYTES, BASE_NONE, NULL, 0x0,
368         NULL, HFILL }},
369
370     { &hf_metamako_seqnum, {
371         "Sequence Number", "metamako.seqnum",
372         FT_UINT16, BASE_DEC, NULL, 0x0,
373         NULL, HFILL }},
374
375     { &hf_metamako_fracns, {
376         "Sub-nanoseconds", "metamako.subns",
377         FT_UINT24, BASE_CUSTOM, CF_FUNC(sub_nanos_base_custom), 0x0,
378         NULL, HFILL }},
379
380     { &hf_metamako_tagstring, {
381         "Tag String", "metamako.tagstring",
382         FT_STRING, BASE_NONE, NULL, 0x0,
383         NULL, HFILL }},
384
385     { &hf_metamako_time, {
386         "Time Stamp", "metamako.time",
387         FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x0,
388         NULL, HFILL }},
389
390     {&hf_metamako_flags, {
391         "Flags", "metamako.flags",
392         FT_UINT8, BASE_HEX, NULL, 0x0,
393         NULL, HFILL}},
394
395     {&hf_metamako_flags_orig_fcs_vld, {
396         "Original FCS Valid", "metamako.flags.orig_fcs_vld",
397         FT_BOOLEAN, 8, TFS(&tfs_valid_invalid), 0x01,
398         NULL, HFILL}},
399
400     {&hf_metamako_flags_has_ext, {
401         "Has Trailer Extensions", "metamako.flags.has_extensions",
402         FT_BOOLEAN, 8, TFS(&tfs_true_false), 0x02,
403         NULL, HFILL}},
404
405     {&hf_metamako_reserved, {
406         "Reserved", "metamako.reserved",
407         FT_UINT8, BASE_HEX, NULL, 0xFC,
408         NULL, HFILL}},
409
410     { &hf_metamako_srcdevice, {
411         "Source Device ID", "metamako.srcdevice",
412         FT_UINT16, BASE_DEC, NULL, 0x0,
413         NULL, HFILL }},
414
415     { &hf_metamako_srcport, {
416         "Source Port", "metamako.srcport",
417         FT_UINT16, BASE_DEC, NULL, 0x0,
418         NULL, HFILL }},
419
420     { &hf_metamako_tdiff, {
421         "Time Difference", "metamako.tdiff",
422         FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
423         "Difference from capture timestamp", HFILL }}
424   };
425
426   static gint *ett[] = {
427     &ett_metamako,
428     &ett_metamako_extensions,
429     &ett_metamako_timestamp,
430     &ett_metamako_flags
431   };
432
433   proto_metamako = proto_register_protocol("Metamako ethernet trailer", "Metamako", "metamako");
434   proto_register_field_array(proto_metamako, hf, array_length(hf));
435   proto_register_subtree_array(ett, array_length(ett));
436 }
437
438 void
439 proto_reg_handoff_metamako(void)
440 {
441   heur_dissector_add("eth.trailer", dissect_metamako, "Metamako ethernet trailer", "metamako_eth", proto_metamako, HEURISTIC_ENABLE);
442 }
443
444 /*
445  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
446  *
447  * Local Variables:
448  * c-basic-offset: 2
449  * tab-width: 8
450  * indent-tabs-mode: nil
451  * End:
452  *
453  * ex: set shiftwidth=2 tabstop=8 expandtab:
454  * :indentSize=2:tabSize=8:noTabs=true:
455  */