FIXUP: WIP: verification_trailer
[wireshark-wip.git] / epan / dissectors / packet-vcdu.c
blobb9d642a66f3a38245f5572f999ba5f3571c414af
1 /* packet-vcdu.c
2 * Routines for VCDU dissection
3 * Copyright 2000, Scott Hovis scott.hovis@ums.msfc.nasa.gov
4 * Enhanced 2008, Matt Dunkle Matthew.L.Dunkle@nasa.gov
6 * $Id$
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.com>
10 * Copyright 1998 Gerald Combs
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include "config.h"
29 #include <glib.h>
30 #include <epan/packet.h>
31 #include <epan/prefs.h>
32 #include <epan/wmem/wmem.h>
33 #include <epan/uat.h>
35 /* Initialize the protocol and registered fields */
36 static int proto_vcdu = -1;
38 static int hf_smex_gsc = -1;
39 /* static int hf_smex_unused = -1; */
40 static int hf_smex_version = -1;
41 static int hf_smex_framelen = -1;
42 static int hf_smex_rs_error = -1;
43 static int hf_smex_rs_enable = -1;
44 static int hf_smex_crc_enable = -1;
45 static int hf_smex_crc_error = -1;
46 static int hf_smex_mcs_enable = -1;
47 static int hf_smex_mcs_num_error = -1;
48 static int hf_smex_data_inv = -1;
49 static int hf_smex_frame_sync = -1;
50 static int hf_smex_data_dir = -1;
51 static int hf_smex_data_class = -1;
52 static int hf_smex_pb5 = -1;
53 static int hf_smex_jday = -1;
54 static int hf_smex_seconds = -1;
55 static int hf_smex_msec = -1;
56 /* static int hf_smex_spare = -1; */
58 static int hf_vcdu_version = -1;
59 static int hf_vcdu_sp_id = -1;
60 static int hf_vcdu_vc_id = -1;
61 static int hf_vcdu_seq = -1;
62 static int hf_vcdu_replay = -1;
64 /* although technically not part of the vcdu header, the
65 * first header pointer (for ccsds), and the last bit
66 * pointer (for bitstream), are more easily processed by
67 * simply adding them to the tail end of the vcdu header
68 * branch rather than creating a distinct branch for them
70 static int hf_vcdu_fhp = -1;
71 static int hf_vcdu_lbp = -1;
73 static dissector_handle_t vcdu_handle;
75 static dissector_handle_t ccsds_handle;
77 /* Initialize the subtree pointers */
78 static gint ett_vcdu = -1;
79 static gint ett_smex = -1;
80 static gint ett_vcduh = -1;
83 * Bits in the first 16-bit header word
85 #define SMEX_VERSION 0xc000
86 #define SMEX_FRAMELEN 0x3fff
88 /* some basic sizing parameters */
89 #define IP_HEADER_LENGTH 48
90 #define SMEX_HEADER_LENGTH 20
91 #define VCDU_HEADER_LENGTH 6
92 #define CCSDS_PRIMARY_HEADER_LENGTH 6
93 #define CCSDS_SECONDARY_HEADER_LENGTH 10
95 #define PB5_JULIAN_DAY_MASK 0x7ffe
96 #define PB5_SECONDS_MASK 0x01ffff
97 #define PB5_MILLISECONDS_MASK 0xffc0
99 #define LBP_ALL_DATA 0x3fff
100 #define LBP_ALL_DATA_ANOMALY 0x7ff
101 #define LBP_ALL_FILL 0x3ffe
103 #define FHP_ALL_FILL 0x7fe
104 #define FHP_CONTINUATION 0x7ff
106 #define LBP_MASK 0x3fff
107 #define FHP_MASK 0x7ff
109 /* leap year macro */
110 #ifndef Leap
111 # define Leap(yr) ( ( 0 == (yr)%4 && 0 != (yr)%100 ) || ( 0 == (yr)%400 ) )
112 #endif
115 static const value_string smex_data_inversion_type[] = {
116 { 0, "Data True (not inverted)" },
117 { 1, "Data Inverted (not corrected)" },
118 { 2, "Data Inversion State UNDEFINED" },
119 { 3, "Data Inverted (and corrected)" },
120 { 0, NULL }
123 static const value_string smex_frame_sync_mode[] = {
124 { 0, "Search" },
125 { 1, "Check" },
126 { 2, "Lock" },
127 { 3, "Flywheel" },
128 { 0, NULL }
131 static const value_string smex_data_direction[] = {
132 { 0, "Forward" },
133 { 1, "Reverse" },
134 { 0, NULL }
137 static const value_string smex_data_class[] = {
138 { 0, "Data Class UNDEFINED" },
139 { 1, "CCSDS Frame" },
140 { 2, "CCSDS Packet" },
141 { 3, "TDM Frame" },
142 { 4, "Stopped TDM Frame" },
143 { 0, NULL }
146 /* default bitstream channel assignments:
147 * the audio channels 4-6 are designated as bitstream channels
148 * the standard bitstream channels are 12 through 19
149 * the video channels 28-30 are designated as bitstream channels
150 * the fill channel 63 is designated as bitstream
152 static int bitstream_channels[] =
154 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* channels 0-9 */
155 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /* channels 10-19 */
156 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* channels 20-29 */
157 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* channels 30-39 */
158 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* channels 40-49 */
159 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* channels 50-59 */
160 0, 0, 0, 1 /* channels 60-63 */
163 typedef struct {
164 guint channel;
165 } uat_channel_t;
167 static uat_channel_t *uat_bitchannels = NULL;
168 static uat_t *vcdu_uat = NULL;
169 static guint num_channels_uat = 0;
171 UAT_DEC_CB_DEF(uat_bitchannels, channel, uat_channel_t)
173 static void
174 vcdu_uat_data_update_cb(void *p, const char **err) {
175 uat_channel_t *ud = (uat_channel_t *)p;
177 if (ud->channel >= 64) {
178 *err = g_strdup("Channel must be between 0-63.");
179 return;
183 static void
184 vcdu_prefs_apply_cb(void)
186 guint i;
188 if (num_channels_uat > 0)
190 memset(bitstream_channels, 0, sizeof(bitstream_channels));
192 for (i = 0; i < num_channels_uat; i++)
194 bitstream_channels[uat_bitchannels[i].channel] = 1;
199 /* convert smex PB5 header time to a human readable string - NOT THREAD SAFE
201 * note: this is not true PB5 time either, but a tsi specific version, although it is similar
203 static const char *
204 smex_time_to_string (int pb5_days_since_midnight_9_10_oct_1995, int pb5_seconds, int pb5_milliseconds)
206 static int utcdiff = 0;
207 nstime_t t;
209 static int Days[2][13] =
211 { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
212 { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
215 int yr;
216 int ix, days, month;
218 /* compute the static constant difference in seconds
219 * between midnight 9-10 October 1995 (PB5 time) and
220 * seconds since 1/1/1970 (UTC time) just this once
222 if (0 == utcdiff)
224 for (yr=1970; yr < 1995; ++yr)
226 utcdiff += (Leap(yr) ? 366 : 365) * 24 * 60 * 60;
229 days = 0;
230 ix = (Leap(1995) ? 1 : 0);
232 for (month=1; month < 10; ++month)
234 days += Days[ix][month];
237 days += 9; /* this gets us up to midnight october 9-10 */
239 utcdiff += days * 24 * 60 * 60; /* add days in 1995 prior to October 10 */
242 t.secs = (pb5_days_since_midnight_9_10_oct_1995 * 86400) + pb5_seconds + utcdiff;
243 t.nsecs = pb5_milliseconds*1000000; /* msecs to nsecs */
245 return abs_time_to_str(&t, ABSOLUTE_TIME_DOY_UTC, TRUE);
249 static void
250 dissect_vcdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
252 int packet_boundary = 0;
253 int offset = 0;
254 int new_offset = 0;
255 int ccsds_tree_added = 0;
256 int ccsds_len = 0;
258 proto_item *smex_header = NULL;
259 proto_tree *smex_tree = NULL;
261 proto_item *vcdu_header = NULL;
262 proto_tree *vcdu_tree = NULL;
264 guint16 first_word = 0;
265 guint32 long_word = 0;
266 guint16 new_ptr = 0;
268 tvbuff_t *new_tvb = NULL;
270 int vcid = 0, pb5_days = 0, pb5_seconds = 0, pb5_milliseconds = 0;
271 const char *time_string = NULL;
273 col_set_str(pinfo->cinfo, COL_PROTOCOL, "VCDU");
274 col_set_str(pinfo->cinfo, COL_INFO, "Virtual Channel Data Unit");
277 /* build the smex header tree */
278 smex_header = proto_tree_add_text(tree, tvb, offset, SMEX_HEADER_LENGTH, "SMEX Header");
279 smex_tree = proto_item_add_subtree(smex_header, ett_smex);
281 proto_tree_add_item(smex_tree, hf_smex_gsc, tvb, offset, 8, ENC_BIG_ENDIAN);
282 offset += 8;
283 /* proto_tree_add_item(smex_tree, hf_smex_unused, tvb, offset, 2, ENC_BIG_ENDIAN); */
284 offset += 2;
286 first_word = tvb_get_ntohs(tvb, offset);
287 proto_tree_add_uint(smex_tree, hf_smex_version, tvb, offset, 2, first_word);
288 proto_tree_add_uint(smex_tree, hf_smex_framelen, tvb, offset, 2, first_word);
289 offset += 2;
291 proto_tree_add_item(smex_tree, hf_smex_rs_enable, tvb, offset, 1, ENC_BIG_ENDIAN);
292 proto_tree_add_item(smex_tree, hf_smex_rs_error, tvb, offset, 1, ENC_BIG_ENDIAN);
293 proto_tree_add_item(smex_tree, hf_smex_crc_enable, tvb, offset, 1, ENC_BIG_ENDIAN);
294 proto_tree_add_item(smex_tree, hf_smex_crc_error, tvb, offset, 1, ENC_BIG_ENDIAN);
295 proto_tree_add_item(smex_tree, hf_smex_mcs_enable, tvb, offset, 1, ENC_BIG_ENDIAN);
296 proto_tree_add_item(smex_tree, hf_smex_mcs_num_error, tvb, offset, 1, ENC_BIG_ENDIAN);
297 proto_tree_add_item(smex_tree, hf_smex_data_inv, tvb, offset, 1, ENC_BIG_ENDIAN);
298 offset += 1;
300 proto_tree_add_item(smex_tree, hf_smex_frame_sync, tvb, offset, 1, ENC_BIG_ENDIAN);
301 proto_tree_add_item(smex_tree, hf_smex_data_dir, tvb, offset, 1, ENC_BIG_ENDIAN);
302 proto_tree_add_item(smex_tree, hf_smex_data_class, tvb, offset, 1, ENC_BIG_ENDIAN);
303 offset += 1;
305 /* extract smex ground receipt time tag */
306 long_word = tvb_get_ntohl(tvb, offset);
307 pb5_days = (long_word >> 17) & PB5_JULIAN_DAY_MASK;
308 pb5_seconds = (long_word & PB5_SECONDS_MASK);
310 first_word = tvb_get_ntohs(tvb, offset+4);
311 pb5_milliseconds = (first_word & PB5_MILLISECONDS_MASK) >> 6;
313 proto_tree_add_item(smex_tree, hf_smex_pb5, tvb, offset, 2, ENC_BIG_ENDIAN);
314 proto_tree_add_item(smex_tree, hf_smex_jday, tvb, offset, 2, ENC_BIG_ENDIAN);
315 offset += 1;
316 proto_tree_add_item(smex_tree, hf_smex_seconds, tvb, offset, 3, ENC_BIG_ENDIAN);
317 offset += 3;
319 proto_tree_add_item(smex_tree, hf_smex_msec, tvb, offset, 2, ENC_BIG_ENDIAN);
320 /* proto_tree_add_item(smex_tree, hf_smex_spare, tvb, offset, 2, ENC_BIG_ENDIAN); */
321 offset += 2;
323 /* format ground receipt time into human readable time format for display */
324 time_string = smex_time_to_string(pb5_days, pb5_seconds, pb5_milliseconds);
325 proto_tree_add_text(smex_tree, tvb, offset-6, 6, "%s = Ground Receipt Time", time_string);
327 proto_item_set_end(smex_header, tvb, offset);
330 /* build the vcdu header tree */
331 vcdu_header = proto_tree_add_text(tree, tvb, offset, VCDU_HEADER_LENGTH, "VCDU Header");
332 vcdu_tree = proto_item_add_subtree(vcdu_header, ett_vcdu);
334 /* extract the virtual channel for use later on */
335 first_word = tvb_get_ntohs(tvb, offset);
336 vcid = first_word & 0x3f;
338 proto_tree_add_item(vcdu_tree, hf_vcdu_version, tvb, offset, 2, ENC_BIG_ENDIAN);
339 proto_tree_add_item(vcdu_tree, hf_vcdu_sp_id, tvb, offset, 2, ENC_BIG_ENDIAN);
340 proto_tree_add_item(vcdu_tree, hf_vcdu_vc_id, tvb, offset, 2, ENC_BIG_ENDIAN);
341 offset += 2;
342 proto_tree_add_item(vcdu_tree, hf_vcdu_seq, tvb, offset, 3, ENC_BIG_ENDIAN);
343 offset += 3;
344 proto_tree_add_item(vcdu_tree, hf_vcdu_replay, tvb, offset, 1, ENC_BIG_ENDIAN);
345 offset += 1;
347 /* extract mpdu/bpdu header word */
348 first_word = tvb_get_ntohs(tvb, offset);
350 /* do bitstream channel processing */
351 if (bitstream_channels[vcid])
353 /* extract last bit pointer for bitstream channels */
354 new_ptr = first_word & LBP_MASK;
356 /* add last bit pointer to display tree */
357 proto_tree_add_item(vcdu_tree, hf_vcdu_lbp, tvb, offset, 2, ENC_BIG_ENDIAN);
359 switch (new_ptr)
361 case LBP_ALL_DATA:
362 proto_tree_add_text(vcdu_tree, tvb, 0, -1, "Bitream ALL Data");
363 break;
365 case LBP_ALL_DATA_ANOMALY:
366 proto_tree_add_text(vcdu_tree, tvb, 0, -1, "Bitream ALL Data (Anomaly)");
367 break;
369 case LBP_ALL_FILL:
370 proto_tree_add_text(vcdu_tree, tvb, 0, -1, "Bitream ALL Fill");
371 break;
373 default:
374 break;
376 } /* end of bitstream channel processing */
378 /* do ccsds channel processing */
379 else
381 /* extract first header pointer for ccsds channels */
382 new_ptr = first_word & FHP_MASK;
384 /* add first header pointer to display tree */
385 proto_tree_add_item(vcdu_tree, hf_vcdu_fhp, tvb, offset, 2, ENC_BIG_ENDIAN);
387 /* process special cases of first header pointer */
388 if (FHP_ALL_FILL == new_ptr)
390 proto_tree_add_text(vcdu_tree, tvb, 0, -1, "Ccsds ALL Fill");
393 else if (FHP_CONTINUATION == new_ptr)
395 proto_tree_add_text(vcdu_tree, tvb, 0, -1, "Ccsds Continuation Packet");
398 /* process as many ccsds packet headers as we can using the ccsds packet dissector */
399 else
401 /* compute offset and packet boundary lengths for ccsds dissector loop */
402 new_offset = offset + 2 + new_ptr;
404 packet_boundary =
405 tvb_reported_length(tvb) - VCDU_HEADER_LENGTH
406 - CCSDS_PRIMARY_HEADER_LENGTH - CCSDS_SECONDARY_HEADER_LENGTH;
408 while ( ((new_offset-offset+2) < packet_boundary) && ((new_offset-offset+2) >= 4) )
410 ccsds_tree_added = 1;
411 ccsds_len = tvb_get_ntohs(tvb, new_offset+4);
413 new_tvb = tvb_new_subset_remaining(tvb, new_offset);
414 call_dissector(ccsds_handle, new_tvb, pinfo, vcdu_tree);
416 new_offset = new_offset + ccsds_len + 7;
419 if (! ccsds_tree_added)
421 proto_tree_add_text(vcdu_tree, tvb, 0, -1,
422 "FHP too close to end of VCDU. Incomplete Hdr Info Available"
423 " - Unable to format CCSDS Hdr(s)." );
427 } /* end of ccsds channel processing */
429 /* don't include the mpdu/bpdu header in the vcdu header highlighting.
430 * by skipping the offset bump the vcdu header highlighting will show
431 * just 6 bytes as it really should, and the fhp/lbp will be included
432 * in the data zone, which is technically more correct.
434 /* offset += 2; */
435 proto_item_set_end(vcdu_tree, tvb, offset);
437 if (! ccsds_tree_added)
439 /* add "Data" section if ccsds parsing did not do so already */
440 proto_tree_add_text(vcdu_tree, tvb, offset, -1, "Data");
446 void
447 proto_register_vcdu(void)
449 module_t *vcdu_module;
451 /* Setup list of header fields See Section 1.6.1 for details*/
452 static hf_register_info hf[] = {
453 { &hf_smex_gsc,
454 { "Ground Sequence Counter", "vcdu.smex.gsc",
455 FT_UINT64, BASE_DEC, NULL, 0x0,
456 "SMEX Ground Sequence Counter", HFILL }
458 #if 0
459 { &hf_smex_unused,
460 { "Unused", "vcdu.smex.unused",
461 FT_UINT16, BASE_DEC, NULL, 0x0,
462 "SMEX Unused", HFILL }
464 #endif
465 { &hf_smex_version,
466 { "Version", "vcdu.smex.version",
467 FT_UINT16, BASE_DEC, NULL, SMEX_VERSION,
468 "SMEX Version", HFILL }
470 { &hf_smex_framelen,
471 { "Frame Length", "vcdu.smex.frame_len",
472 FT_UINT16, BASE_DEC, NULL, SMEX_FRAMELEN,
473 "SMEX Frame Length", HFILL }
475 { &hf_smex_rs_enable,
476 { "RS Enable", "vcdu.smex.rs_enable",
477 FT_BOOLEAN, 8, NULL, 0x80,
478 "SMEX RS Enable", HFILL }
480 { &hf_smex_rs_error,
481 { "RS Error", "vcdu.smex.rs_error",
482 FT_BOOLEAN, 8, NULL, 0x40,
483 "SMEX RS Error", HFILL }
485 { &hf_smex_crc_enable,
486 { "CRC Enable", "vcdu.smex.crc_enable",
487 FT_BOOLEAN, 8, NULL, 0x20,
488 "SMEX CRC Enable", HFILL }
490 { &hf_smex_crc_error,
491 { "CRC Error", "vcdu.smex.crc_error",
492 FT_BOOLEAN, 8, NULL, 0x10,
493 "SMEX CRC Error", HFILL }
495 { &hf_smex_mcs_enable,
496 { "MCS Enable", "vcdu.smex.mcs_enable",
497 FT_BOOLEAN, 8, NULL, 0x08,
498 "SMEX MCS Enable", HFILL }
500 { &hf_smex_mcs_num_error,
501 { "MCS Number Error", "vcdu.smex.mcs_numerr",
502 FT_BOOLEAN, 8, NULL, 0x04,
503 "SMEX MCS Number Error", HFILL }
505 { &hf_smex_data_inv,
506 { "Data Inversion", "vcdu.smex.data_inv",
507 FT_UINT16, BASE_DEC, VALS(smex_data_inversion_type), 0x03,
508 "SMEX Data Inversion", HFILL }
510 { &hf_smex_frame_sync,
511 { "Frame Sync", "vcdu.smex.frame_sync",
512 FT_UINT16, BASE_DEC, VALS(smex_frame_sync_mode), 0xc0,
513 "SMEX Frame Sync Flag", HFILL }
515 { &hf_smex_data_dir,
516 { "Data Direction", "vcdu.smex.data_dir",
517 FT_UINT16, BASE_DEC, VALS(smex_data_direction), 0x20,
518 "SMEX Data Direction flag", HFILL }
520 { &hf_smex_data_class,
521 { "Data Class", "vcdu.smex.data_class",
522 FT_UINT16, BASE_DEC, VALS(smex_data_class), 0x1f,
523 "SMEX Data Class", HFILL }
525 { &hf_smex_pb5,
526 { "PB5 Flag", "vcdu.smex.pb5",
527 FT_UINT16, BASE_DEC, NULL, 0x8000,
528 "SMEX PB5 Flag", HFILL }
530 { &hf_smex_jday,
531 { "Julian Day", "vcdu.smex.jday",
532 FT_UINT16, BASE_DEC, NULL, PB5_JULIAN_DAY_MASK,
533 "SMEX Julian Day", HFILL }
535 { &hf_smex_seconds,
536 { "Seconds", "vcdu.smex.seconds",
537 FT_UINT24, BASE_DEC, NULL, PB5_SECONDS_MASK,
538 "SMEX Seconds", HFILL }
540 { &hf_smex_msec,
541 { "Milliseconds", "vcdu.smex.msec",
542 FT_UINT16, BASE_DEC, NULL, PB5_MILLISECONDS_MASK,
543 "SMEX Milliseconds", HFILL }
545 #if 0
546 { &hf_smex_spare,
547 { "Spare", "vcdu.smex.spare",
548 FT_UINT16, BASE_DEC, NULL, 0x03f,
549 "SMEX Spare", HFILL }
551 #endif
553 { &hf_vcdu_version,
554 { "Version", "vcdu.version",
555 FT_UINT16, BASE_DEC, NULL, 0xc0,
556 "VCDU Version", HFILL }
558 { &hf_vcdu_sp_id,
559 { "Space Craft ID", "vcdu.spid",
560 FT_UINT16, BASE_DEC, NULL, 0x3fc0,
561 "VCDU Space Craft ID", HFILL }
563 { &hf_vcdu_vc_id,
564 { "Virtual Channel ID", "vcdu.vcid",
565 FT_UINT16, BASE_DEC, NULL, 0x3f,
566 "VCDU Virtual Channel ID", HFILL }
568 { &hf_vcdu_seq,
569 { "Sequence Count", "vcdu.seq",
570 FT_UINT16, BASE_DEC, NULL, 0xffffff,
571 "VCDU Sequence Count", HFILL }
573 { &hf_vcdu_replay,
574 { "Replay Flag", "vcdu.replay",
575 FT_BOOLEAN, 8, NULL, 0x80,
576 "VCDU Replay Flag", HFILL }
579 /* not really part of the vcdu header, but it's easier this way */
580 { &hf_vcdu_fhp,
581 { "First Header Pointer", "vcdu.fhp",
582 FT_UINT16, BASE_DEC, NULL, FHP_MASK,
583 "VCDU/MPDU First Header Pointer", HFILL }
585 { &hf_vcdu_lbp,
586 { "Last Bit Pointer", "vcdu.lbp",
587 FT_UINT16, BASE_DEC, NULL, LBP_MASK,
588 "VCDU/BPDU Last Bit Pointer", HFILL }
592 static uat_field_t vcdu_uat_flds[] = {
593 UAT_FLD_DEC(uat_bitchannels, channel, "Bitstream Channel", "Bitstream Channel"),
594 UAT_END_FIELDS
597 /* Setup protocol subtree array */
598 static gint *ett[] = {
599 &ett_vcdu,
600 &ett_smex,
601 &ett_vcduh,
604 /* Register the protocol name and description */
605 proto_vcdu = proto_register_protocol("VCDU", "VCDU", "vcdu");
607 /* Required function calls to register the header fields and subtrees used */
608 proto_register_field_array(proto_vcdu, hf, array_length(hf));
609 proto_register_subtree_array(ett, array_length(ett));
611 /* XX: Does this dissector need to be publicly registered ?? */
612 vcdu_handle = register_dissector("vcdu", dissect_vcdu, proto_vcdu);
614 vcdu_module = prefs_register_protocol(proto_vcdu, vcdu_prefs_apply_cb);
616 vcdu_uat = uat_new("Bitstream Channel Table",
617 sizeof(uat_channel_t),
618 "vcdu_bitstream_channels",
619 TRUE,
620 (void**)&uat_bitchannels,
621 &num_channels_uat,
622 UAT_AFFECTS_DISSECTION, /* affects dissection of packets, but not set of named fields */
623 NULL,
624 NULL,
625 vcdu_uat_data_update_cb,
626 NULL,
627 NULL,
628 vcdu_uat_flds);
630 prefs_register_uat_preference(vcdu_module,
631 "bitstream_channels",
632 "Bitstream Channel Table",
633 "Bitstream Channel Table",
634 vcdu_uat);
639 void
640 proto_reg_handoff_vcdu(void)
642 dissector_add_handle("udp.port", vcdu_handle); /* for 'decode as' */
643 ccsds_handle = find_dissector("ccsds");