HACK: 2nd try to match RowsetProperties
[wireshark-wip.git] / epan / dissectors / packet-gmhdr.c
blob5f4276e7a7824177130f882fa1f5f5e90c9956f2
1 /* packet-gmhdr.c
2 * Routines for Gigamon header disassembly (modified from packet-vlan.c)
4 * Dissector for Gigamon Header and Trailer
5 * Copyright Gigamon 2010
7 * $Id$
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1998 Gerald Combs
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 #include "config.h"
30 #include <epan/packet.h>
31 #include <epan/etypes.h>
32 #include <epan/prefs.h>
33 #include <epan/in_cksum.h>
34 #include <epan/crc32-tvb.h>
35 #include <wsutil/crc32.h>
36 #include <wsutil/pint.h>
37 #include <epan/expert.h>
39 #include "packet-ieee8023.h"
41 #define GMHDR_FTYPE_PKTSIZE 1
42 #define GMHDR_FTYPE_SRCPORT_G 2
43 #define GMHDR_FTYPE_TIMESTAMP_LOCAL 3
44 #define GMHDR_FTYPE_TIMESTAMP_NTP 4
45 #define GMHDR_FTYPE_TIMESTAMP_GPS 5
46 #define GMHDR_FTYPE_TIMESTAMP_1588 6
47 #define GMHDR_FTYPE_FCS 7
48 #define GMHDR_FTYPE_SRCPORT_H 8
50 static const value_string gmhdr_ftype_timestamp[] = {
51 { GMHDR_FTYPE_TIMESTAMP_LOCAL, "Local" },
52 { GMHDR_FTYPE_TIMESTAMP_NTP, "NTP" },
53 { GMHDR_FTYPE_TIMESTAMP_GPS, "GPS" },
54 { GMHDR_FTYPE_TIMESTAMP_1588, "1588" },
55 { 0, NULL }
58 #define GMHDR_SRCPORT_G_PLFM_MASK 0x00f80000
59 #define GMHDR_SRCPORT_G_GID_MASK 0x00078000
60 #define GMHDR_SRCPORT_G_BID_MASK 0x00007c00
61 #define GMHDR_SRCPORT_G_PID_MASK 0x000003ff
62 #define GMHDR_SRCPORT_G_PLFM_SHFT 19
63 #define GMHDR_SRCPORT_G_GID_SHFT 15
64 #define GMHDR_SRCPORT_G_BID_SHFT 10
65 #define GMHDR_SRCPORT_G_PID_SHFT 0
67 #define GMHDR_SRCPORT_H_PLFM_MASK 0xFC000000
68 #define GMHDR_SRCPORT_H_GID_MASK 0x03C00000
69 #define GMHDR_SRCPORT_H_BID_MASK 0x003F0000
70 #define GMHDR_SRCPORT_H_SID_MASK 0x0000FC00
71 #define GMHDR_SRCPORT_H_PID_MASK 0x000003FF
72 #define GMHDR_SRCPORT_H_PLFM_SHFT 26
73 #define GMHDR_SRCPORT_H_GID_SHFT 20
74 #define GMHDR_SRCPORT_H_BID_SHFT 16
75 #define GMHDR_SRCPORT_H_SID_SHFT 10
76 #define GMHDR_SRCPORT_H_PID_SHFT 0
78 static const value_string gmhdr_plfm_str[] = {
79 { 0, "Reserved" },
80 { 1, "GV-2404" },
81 { 2, "GV-420" },
82 { 3, "GV-MP" },
83 { 4, "HD4" },
84 { 5, "HD8" },
85 { 6, "GV-212" },
86 { 7, "HB1" },
87 { 8, "HC2" },
88 { 0, NULL }
91 static gboolean gmhdr_summary_in_tree = TRUE;
92 static gboolean gmtrailer_summary_in_tree = TRUE;
93 static gboolean gmhdr_decode_timestamp_trailer = TRUE;
95 static int proto_gmhdr = -1;
96 static int proto_gmtrailer = -1;
97 static int hf_gmhdr_srcport_g = -1;
98 static int hf_gmhdr_srcport_g_plfm = -1;
99 static int hf_gmhdr_srcport_g_gid = -1;
100 static int hf_gmhdr_srcport_g_bid = -1;
101 static int hf_gmhdr_srcport_g_pid = -1;
102 static int hf_gmhdr_pktsize = -1;
103 static int hf_gmhdr_timestamp = -1;
104 static int hf_gmhdr_generic = -1;
105 static int hf_gmhdr_etype = -1;
106 static int hf_gmhdr_len = -1;
107 static int hf_gmhdr_trailer = -1;
108 static int hf_gmhdr_origcrc = -1;
109 static int hf_gmhdr_srcport_h = -1;
110 static int hf_gmhdr_srcport_h_plfm = -1;
111 static int hf_gmhdr_srcport_h_gid = -1;
112 static int hf_gmhdr_srcport_h_bid = -1;
113 static int hf_gmhdr_srcport_h_sid = -1;
114 static int hf_gmhdr_srcport_h_pid = -1;
116 static int hf_gmtrailer_origcrc = -1;
117 static int hf_gmtrailer_portid = -1;
118 static int hf_gmtrailer_timestamp = -1;
120 static gint ett_gmhdr = -1;
121 static gint ett_srcport = -1;
122 static gint ett_gmtrailer = -1;
124 static expert_field ei_gmhdr_field_length_invalid = EI_INIT;
125 static expert_field ei_gmhdr_len = EI_INIT;
127 static void
128 dissect_gmtlv(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *gmhdr_tree, guint offset, guint16 length)
130 proto_tree *ti;
131 proto_tree *srcport_tree;
132 guint16 fl;
134 while (length > 1) {
135 guint16 tl = tvb_get_ntohs(tvb, offset);
136 offset += 2; /* type + len */
137 length -= 2;
139 fl = tl & 0xff;
140 switch (tl >> 8) {
141 case GMHDR_FTYPE_SRCPORT_G: {
142 guint16 pid;
143 guint32 tv = tvb_get_ntohl(tvb, offset) >> 8; /* Only 24-bit field */
145 if (fl != 3) {
146 expert_add_info_format(pinfo, gmhdr_tree, &ei_gmhdr_field_length_invalid, "Field length %u invalid", fl);
147 break;
149 ti = proto_tree_add_item(gmhdr_tree, hf_gmhdr_srcport_g, tvb, offset, fl, ENC_BIG_ENDIAN);
150 srcport_tree = proto_item_add_subtree(ti, ett_srcport);
151 proto_tree_add_item(srcport_tree, hf_gmhdr_srcport_g_plfm, tvb, offset, fl, ENC_BIG_ENDIAN);
152 proto_tree_add_item(srcport_tree, hf_gmhdr_srcport_g_gid, tvb, offset, fl, ENC_BIG_ENDIAN);
153 proto_tree_add_item(srcport_tree, hf_gmhdr_srcport_g_bid, tvb, offset, fl, ENC_BIG_ENDIAN);
154 ti = proto_tree_add_item(srcport_tree, hf_gmhdr_srcport_g_pid, tvb, offset, fl, ENC_BIG_ENDIAN);
155 /* If not GV-2404, we need different formula here */
156 pid = ((tv & GMHDR_SRCPORT_G_PID_MASK) >> GMHDR_SRCPORT_G_PID_SHFT) - 24;
157 if (pid >= 1 && pid <= 4) {
158 proto_item_append_text(ti, " (g%d)", pid);
160 break;
162 case GMHDR_FTYPE_PKTSIZE:
163 if (fl != 2) {
164 expert_add_info_format(pinfo, gmhdr_tree, &ei_gmhdr_field_length_invalid, "Field length %u invalid", fl);
165 break;
167 proto_tree_add_item(gmhdr_tree, hf_gmhdr_pktsize, tvb, offset, fl, ENC_BIG_ENDIAN);
168 break;
169 case GMHDR_FTYPE_TIMESTAMP_LOCAL:
170 case GMHDR_FTYPE_TIMESTAMP_NTP:
171 case GMHDR_FTYPE_TIMESTAMP_GPS:
172 case GMHDR_FTYPE_TIMESTAMP_1588:
173 if (fl != 8) {
174 expert_add_info_format(pinfo, gmhdr_tree, &ei_gmhdr_field_length_invalid, "Field length %u invalid", fl);
175 break;
177 ti = proto_tree_add_item(gmhdr_tree, hf_gmhdr_timestamp, tvb, offset, fl, ENC_TIME_TIMESPEC|ENC_BIG_ENDIAN);
178 proto_item_append_text(ti, "; Source: %s", val_to_str_const(tl>>8, gmhdr_ftype_timestamp, "Unknown"));
179 break;
180 case GMHDR_FTYPE_FCS: {
181 if (fl != 4) {
182 expert_add_info_format(pinfo, gmhdr_tree, &ei_gmhdr_field_length_invalid, "Field length %u invalid", fl);
183 break;
185 ti = proto_tree_add_item(gmhdr_tree, hf_gmhdr_origcrc, tvb, offset, 4, ENC_BIG_ENDIAN);
186 proto_item_append_text(ti, ", CRC (Not Verified)");
187 break;
189 case GMHDR_FTYPE_SRCPORT_H: {
190 if (fl != 4) {
191 expert_add_info_format(pinfo, gmhdr_tree, &ei_gmhdr_field_length_invalid, "Field length %u invalid", fl);
192 break;
194 ti = proto_tree_add_item(gmhdr_tree, hf_gmhdr_srcport_h, tvb, offset, fl, ENC_BIG_ENDIAN);
195 srcport_tree = proto_item_add_subtree(ti, ett_srcport);
196 proto_tree_add_item(srcport_tree, hf_gmhdr_srcport_h_plfm, tvb, offset, fl, ENC_BIG_ENDIAN);
197 proto_tree_add_item(srcport_tree, hf_gmhdr_srcport_h_gid, tvb, offset, fl, ENC_BIG_ENDIAN);
198 proto_tree_add_item(srcport_tree, hf_gmhdr_srcport_h_bid, tvb, offset, fl, ENC_BIG_ENDIAN);
199 proto_tree_add_item(srcport_tree, hf_gmhdr_srcport_h_sid, tvb, offset, fl, ENC_BIG_ENDIAN);
200 proto_tree_add_item(srcport_tree, hf_gmhdr_srcport_h_pid, tvb, offset, fl, ENC_BIG_ENDIAN);
201 break;
203 default:
204 ti = proto_tree_add_item(gmhdr_tree, hf_gmhdr_generic, tvb, offset, fl, ENC_NA);
205 proto_item_append_text(ti, " [Id: %u, Length: %u]", tl >> 8, fl);
206 break;
208 /* Adjust for the field length */
209 offset += fl;
210 length -= fl;
216 static void
217 dissect_gmhdr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
219 proto_tree *ti;
220 gint16 length;
221 volatile guint16 encap_proto;
222 volatile gboolean is_802_2;
223 proto_tree *volatile gmhdr_tree = NULL;
224 volatile guint offset = 0;
226 length = tvb_get_guint8(tvb, offset); /* Length of the Gigamon header */
228 if (tree) {
229 ti = proto_tree_add_item(tree, proto_gmhdr, tvb, offset, length, ENC_NA);
231 if (gmhdr_summary_in_tree) {
232 proto_item_append_text(ti, ", Length: %u", length);
235 gmhdr_tree = proto_item_add_subtree(ti, ett_gmhdr);
236 dissect_gmtlv(tvb, pinfo, gmhdr_tree, offset+1, length-1);
238 } /* if (tree) */
240 offset += length;
241 encap_proto = tvb_get_ntohs(tvb, offset);
242 offset += 2;
243 if (encap_proto <= IEEE_802_3_MAX_LEN) {
244 /* Is there an 802.2 layer? I can tell by looking at the first 2
245 bytes after the GMHDR header. If they are 0xffff, then what
246 follows the GMHDR header is an IPX payload, meaning no 802.2.
247 (IPX/SPX is they only thing that can be contained inside a
248 straight 802.3 packet, so presumably the same applies for
249 Ethernet GMHDR packets). A non-0xffff value means that there's an
250 802.2 layer inside the GMHDR layer */
251 is_802_2 = TRUE;
253 /* Don't throw an exception for this check (even a BoundsError) */
254 if (tvb_length_remaining(tvb, offset) >= 2) {
255 if (tvb_get_ntohs(tvb, offset) == 0xffff) {
256 is_802_2 = FALSE;
260 dissect_802_3(encap_proto, is_802_2, tvb, offset, pinfo, tree, gmhdr_tree,
261 hf_gmhdr_len, hf_gmhdr_trailer, &ei_gmhdr_len, 0);
262 } else {
263 ethertype(encap_proto, tvb, offset, pinfo, tree, gmhdr_tree,
264 hf_gmhdr_etype, hf_gmhdr_trailer, 0);
268 static int
269 dissect_gmtimestamp_trailer(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
271 proto_tree *ti;
272 guint tvblen, trailer_len = 18;
273 proto_tree *gmtrailer_tree = NULL;
274 guint offset = 0;
275 guint32 orig_crc, new_crc, comp_crc;
276 guint16 port_num;
277 nstime_t gmtimev;
279 struct tm *tm = NULL;
281 if ( ! gmhdr_decode_timestamp_trailer)
282 return 0;
284 /* See if this packet has a Gigamon trailer, if yes, then decode it */
285 /* (Don't throw any exceptions while checking for the trailer). */
286 tvblen = tvb_length(tvb); /* end+1 */
287 if (tvblen < trailer_len)
288 return 0;
290 orig_crc = tvb_get_ntohl(tvb, offset);
291 new_crc = tvb_get_ntohl(tvb, tvblen - 4);
293 /* Verify the checksum; if not valid, it means that the trailer is not valid */
294 comp_crc = CRC32C_SWAP(crc32_ccitt_tvb_seed(tvb, 14, CRC32C_SWAP(~orig_crc)));
295 if (comp_crc != new_crc)
296 return 0;
298 /* OK: We appear to have a Gigamon trailer */
299 if (tree) {
300 ti = proto_tree_add_item(tree, proto_gmtrailer, tvb, offset, trailer_len - 4, ENC_NA);
302 if (gmtrailer_summary_in_tree) {
303 offset += 4;
304 port_num = tvb_get_ntohs(tvb, offset);
305 offset += 2;
306 gmtimev.secs = tvb_get_ntohl(tvb, offset);
307 offset += 4;
308 gmtimev.nsecs = tvb_get_ntohl(tvb, offset);
310 tm = localtime(&gmtimev.secs);
311 proto_item_append_text(ti, ", Port: %d, Timestamp: %d:%d:%d.%d", port_num, tm->tm_hour, tm->tm_min, tm->tm_sec, gmtimev.nsecs);
314 offset = 0;
315 gmtrailer_tree = proto_item_add_subtree(ti, ett_gmtrailer);
316 proto_tree_add_item(gmtrailer_tree, hf_gmtrailer_origcrc, tvb, offset, 4, ENC_BIG_ENDIAN);
317 proto_tree_add_item(gmtrailer_tree, hf_gmtrailer_portid, tvb, offset+4, 2, ENC_BIG_ENDIAN);
318 proto_tree_add_item(gmtrailer_tree, hf_gmtrailer_timestamp, tvb, offset+6, 8, ENC_TIME_TIMESPEC|ENC_BIG_ENDIAN);
321 return 14;
324 static int
325 dissect_gmtrailer(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
327 proto_tree *ti;
328 guint tvblen, length;
329 proto_tree *gmhdr_tree = NULL;
330 guint offset;
331 guint16 cksum, comp_cksum, extra_trailer;
333 /* See if this packet has a Gigamon trailer, if yes, then decode it */
334 /* (Don't throw any exceptions while checking for the trailer). */
335 tvblen = tvb_length(tvb); /* end+1 */
336 if (tvblen < 5)
337 return 0;
338 extra_trailer = 0;
339 if (tvb_get_ntohs(tvb, tvblen-4) != ETHERTYPE_GIGAMON) {
340 if (tvblen < 10){
341 return 0;
343 if (tvb_get_ntohs(tvb, tvblen-8) == ETHERTYPE_GIGAMON) {
344 extra_trailer = 4;
345 } else {
346 return 0;
349 length = tvb_get_guint8(tvb, tvblen-extra_trailer-5); /* length of Gigamon header */
350 if ((tvblen-extra_trailer-5) != length)
351 return 0;
353 offset = tvblen - extra_trailer - 5 - length;
355 cksum = tvb_get_ntohs(tvb, tvblen-extra_trailer-2);
357 /* Verify the checksum; if not valid, it means that the trailer is not valid */
359 vec_t vec;
360 vec.len = length + 3;
361 vec.ptr = tvb_get_ptr(tvb, offset, vec.len);
363 comp_cksum = in_cksum(&vec, 1);
364 if (pntohs(&comp_cksum) != cksum) {
365 return 0;
369 /* OK: We appear to have a Gigamon trailer */
370 if (tree) {
371 ti = proto_tree_add_item(tree, proto_gmhdr, tvb, offset, length + 5, ENC_NA);
373 if (gmhdr_summary_in_tree) {
374 proto_item_append_text(ti, ", Length: %u, Checksum: 0x%x", length, cksum);
377 gmhdr_tree = proto_item_add_subtree(ti, ett_gmhdr);
379 dissect_gmtlv(tvb, pinfo, gmhdr_tree, offset, length);
380 if (extra_trailer) {
381 proto_tree_add_item(tree, hf_gmhdr_trailer, tvb, length + 5, extra_trailer, ENC_BIG_ENDIAN);
384 return tvblen;
387 void
388 proto_register_gmhdr(void)
390 static hf_register_info hf[] = {
391 { &hf_gmhdr_srcport_g, {
392 "Src Port", "gmhdr.srcport_g", FT_UINT24, BASE_HEX,
393 NULL, 0, "Original Source Port", HFILL }},
394 { &hf_gmhdr_srcport_g_plfm, {
395 "Platform Id", "gmhdr.srcport_g_plfm", FT_UINT24, BASE_DEC,
396 VALS(gmhdr_plfm_str), GMHDR_SRCPORT_G_PLFM_MASK, "Original Platform Id", HFILL }},
397 { &hf_gmhdr_srcport_g_gid, {
398 "Group Id", "gmhdr.srcport_g_gid", FT_UINT24, BASE_DEC,
399 NULL, GMHDR_SRCPORT_G_GID_MASK, "Original Source Group Id", HFILL }},
400 { &hf_gmhdr_srcport_g_bid, {
401 "Box Id", "gmhdr.srcport_g_bid", FT_UINT24, BASE_DEC,
402 NULL, GMHDR_SRCPORT_G_BID_MASK, "Original Source Box Id", HFILL }},
403 { &hf_gmhdr_srcport_g_pid, {
404 "Port Id", "gmhdr.srcport_g_pid", FT_UINT24, BASE_DEC,
405 NULL, GMHDR_SRCPORT_G_PID_MASK, "Original Source Port Id", HFILL }},
406 { &hf_gmhdr_pktsize, {
407 "Original Packet Size", "gmhdr.pktsize", FT_UINT16, BASE_DEC,
408 NULL, 0, NULL, HFILL }},
409 { &hf_gmhdr_timestamp, {
410 "Time Stamp", "gmhdr.timestamp", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
411 NULL, 0x0, NULL, HFILL }},
412 { &hf_gmhdr_generic, {
413 "Generic Field", "gmhdr.generic", FT_BYTES, BASE_NONE,
414 NULL, 0x0, NULL, HFILL }},
415 { &hf_gmhdr_etype, {
416 "Type", "gmhdr.etype", FT_UINT16, BASE_HEX,
417 VALS(etype_vals), 0x0, "Ethertype", HFILL }},
418 { &hf_gmhdr_len, {
419 "Length", "gmhdr.len", FT_UINT16, BASE_DEC,
420 NULL, 0x0, NULL, HFILL }},
421 { &hf_gmhdr_origcrc, {
422 "Original CRC", "gmhdr.crc", FT_UINT32, BASE_HEX,
423 NULL, 0x0, "Original Packet CRC", HFILL }},
424 { &hf_gmhdr_srcport_h, {
425 "Src Port", "gmhdr.srcport", FT_UINT32, BASE_HEX,
426 NULL, 0, "Original Source Port", HFILL }},
427 { &hf_gmhdr_srcport_h_plfm, {
428 "Platform Id", "gmhdr.srcport_plfm", FT_UINT32, BASE_DEC,
429 VALS(gmhdr_plfm_str), GMHDR_SRCPORT_H_PLFM_MASK, "Original Platform Id", HFILL }},
430 { &hf_gmhdr_srcport_h_gid, {
431 "Group Id", "gmhdr.srcport_gid", FT_UINT32, BASE_DEC,
432 NULL, GMHDR_SRCPORT_H_GID_MASK, "Original Source Group Id", HFILL }},
433 { &hf_gmhdr_srcport_h_bid, {
434 "Box Id", "gmhdr.srcport_bid", FT_UINT32, BASE_DEC,
435 NULL, GMHDR_SRCPORT_H_BID_MASK, "Original Source Box Id", HFILL }},
436 { &hf_gmhdr_srcport_h_sid, {
437 "Slot Id", "gmhdr.srcport_sid", FT_UINT32, BASE_DEC,
438 NULL, GMHDR_SRCPORT_H_SID_MASK, "Original Source Slot Id", HFILL }},
439 { &hf_gmhdr_srcport_h_pid, {
440 "Port Id", "gmhdr.srcport_pid", FT_UINT32, BASE_DEC,
441 NULL, GMHDR_SRCPORT_H_PID_MASK, "Original Source Port Id", HFILL }},
442 { &hf_gmhdr_trailer, {
443 "Trailer", "gmhdr.trailer", FT_BYTES, BASE_NONE,
444 NULL, 0x0, "GMHDR Trailer", HFILL }},
446 static hf_register_info gmtrailer_hf[] = {
447 { &hf_gmtrailer_origcrc, {
448 "Original CRC", "gmtrailer.crc", FT_UINT32, BASE_HEX,
449 NULL, 0x0, "Original Packet CRC", HFILL }},
450 { &hf_gmtrailer_portid, {
451 "Src Port", "gmtrailer.portid", FT_UINT16, BASE_HEX,
452 NULL, 0x0, "Origin Source Port", HFILL }},
453 { &hf_gmtrailer_timestamp, {
454 "Time Stamp", "gmtrailer.timestamp", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
455 NULL, 0x0, NULL, HFILL }},
457 static gint *ett[] = {
458 &ett_gmhdr,
459 &ett_srcport
461 static gint *gmtrailer_ett[] = {
462 &ett_gmtrailer,
464 static ei_register_info ei[] = {
465 { &ei_gmhdr_field_length_invalid, { "gmhdr.field_length_invalid", PI_MALFORMED, PI_ERROR, "Field length invalid", EXPFILL }},
466 { &ei_gmhdr_len, { "gmhdr.len.past_end", PI_MALFORMED, PI_ERROR, "Length field value goes past the end of the payload", EXPFILL }},
469 module_t *gmhdr_module;
470 module_t *gmtrailer_module;
471 expert_module_t* expert_gmhdr;
473 proto_gmhdr = proto_register_protocol("Gigamon Header", "GMHDR", "gmhdr");
474 proto_register_field_array(proto_gmhdr, hf, array_length(hf));
475 proto_register_subtree_array(ett, array_length(ett));
476 expert_gmhdr = expert_register_protocol(proto_gmhdr);
477 expert_register_field_array(expert_gmhdr, ei, array_length(ei));
479 proto_gmtrailer = proto_register_protocol("Gigamon Trailer", "GMTRAILER", "gmtrailer");
480 proto_register_field_array(proto_gmtrailer, gmtrailer_hf, array_length(gmtrailer_hf));
481 proto_register_subtree_array(gmtrailer_ett, array_length(gmtrailer_ett));
483 gmhdr_module = prefs_register_protocol(proto_gmhdr, NULL);
484 prefs_register_bool_preference(gmhdr_module, "summary_in_tree",
485 "Show Gigamon header summary in protocol tree",
486 "Whether the Gigamon header summary line should be shown in the protocol tree",
487 &gmhdr_summary_in_tree);
489 gmtrailer_module = prefs_register_protocol(proto_gmtrailer, NULL);
490 prefs_register_bool_preference(gmtrailer_module, "summary_in_tree",
491 "Show Gigamon Trailer summary in protocol tree",
492 "Whether the Gigamon Trailer summary line should be shown in the protocol tree",
493 &gmtrailer_summary_in_tree);
494 prefs_register_bool_preference(gmtrailer_module, "decode_trailer_timestamp",
495 "Decode Gigamon HW timestamp and source id in trailer",
496 "Whether the Gigamon trailer containing HW timestamp, source id and original CRC should be decoded",
497 &gmhdr_decode_timestamp_trailer);
500 void
501 proto_reg_handoff_gmhdr(void)
503 dissector_handle_t gmhdr_handle;
505 gmhdr_handle = create_dissector_handle(dissect_gmhdr, proto_gmhdr);
506 dissector_add_uint("ethertype", ETHERTYPE_GIGAMON, gmhdr_handle);
507 heur_dissector_add("eth.trailer", dissect_gmtrailer, proto_gmhdr);
509 heur_dissector_add("eth.trailer", dissect_gmtimestamp_trailer, proto_gmtrailer);