diff options
author | Anders Broman <anders.broman@ericsson.com> | 2009-03-18 07:29:36 +0000 |
---|---|---|
committer | Anders Broman <anders.broman@ericsson.com> | 2009-03-18 07:29:36 +0000 |
commit | 26e5b929fa4bb0e18c300b4a74ec10e74fda36fb (patch) | |
tree | a6b05c6b4b232f08a8ab2a61550971184c62241f | |
parent | 2d24475011b4e147bd2b1bac18d62c7226aa17e7 (diff) | |
download | wireshark-26e5b929fa4bb0e18c300b4a74ec10e74fda36fb.tar.gz |
From Patrick A Baldwin:
Enhancements for CCSDS Dissectors.
svn path=/trunk/; revision=27768
-rw-r--r-- | epan/dissectors/packet-ccsds.c | 543 | ||||
-rw-r--r-- | epan/dissectors/packet-ehs.c | 1924 | ||||
-rw-r--r-- | epan/dissectors/packet-vcdu.c | 648 |
3 files changed, 3019 insertions, 96 deletions
diff --git a/epan/dissectors/packet-ccsds.c b/epan/dissectors/packet-ccsds.c index 428ada6f15..8176193719 100644 --- a/epan/dissectors/packet-ccsds.c +++ b/epan/dissectors/packet-ccsds.c @@ -1,6 +1,7 @@ /* packet-ccsds.c * Routines for CCSDS dissection * Copyright 2000, Scott Hovis scott.hovis@ums.msfc.nasa.gov + * Enhanced 2008, Matt Dunkle Matthew.L.Dunkle@nasa.gov * * $Id$ * @@ -32,19 +33,20 @@ #include <string.h> #include <glib.h> - #include <epan/packet.h> + /* * See * - * http://public.ccsds.org/publications/archive/133x0b1.pdf section 4.1 - * - * for some information. + * http://stationpayloads.jsc.nasa.gov/J-reference/documents/ssp57002B.pdf */ + /* Initialize the protocol and registered fields */ static int proto_ccsds = -1; + +/* primary ccsds header */ static int hf_ccsds_apid = -1; static int hf_ccsds_version = -1; static int hf_ccsds_secheader = -1; @@ -52,18 +54,34 @@ static int hf_ccsds_type = -1; static int hf_ccsds_seqnum = -1; static int hf_ccsds_seqflag = -1; static int hf_ccsds_length = -1; -static int hf_ccsds_time = -1; + +/* common ccsds secondary header */ +static int hf_ccsds_coarse_time = -1; +static int hf_ccsds_fine_time = -1; static int hf_ccsds_timeid = -1; static int hf_ccsds_checkword = -1; + +/* payload specific ccsds secondary header */ static int hf_ccsds_zoe = -1; -static int hf_ccsds_packtype = -1; +static int hf_ccsds_packet_type_unused = -1; static int hf_ccsds_vid = -1; static int hf_ccsds_dcc = -1; +/* core specific ccsds secondary header */ +static int hf_ccsds_spare1 = -1; +static int hf_ccsds_packet_type = -1; +static int hf_ccsds_spare2 = -1; +static int hf_ccsds_element_id = -1; +static int hf_ccsds_cmd_data_packet = -1; +static int hf_ccsds_format_version_id = -1; +static int hf_ccsds_extended_format_id = -1; +static int hf_ccsds_spare3 = -1; +static int hf_ccsds_frame_id = -1; + /* Initialize the subtree pointers */ static gint ett_ccsds = -1; -static gint ett_header = -1; -static gint ett_header2 = -1; +static gint ett_ccsds_primary_header = -1; +static gint ett_ccsds_secondary_header = -1; /* * Bits in the first 16-bit header word @@ -73,185 +91,518 @@ static gint ett_header2 = -1; #define HDR_SECHDR 0x0800 #define HDR_APID 0x07ff +/* some basic sizing parameters */ +enum +{ + IP_HEADER_LENGTH = 48, + VCDU_HEADER_LENGTH = 6, + CCSDS_PRIMARY_HEADER_LENGTH = 6, + CCSDS_SECONDARY_HEADER_LENGTH = 10 +}; + +/* leap year macro */ +#ifndef Leap +# define Leap(yr) ( ( 0 == (yr)%4 && 0 != (yr)%100 ) || ( 0 == (yr)%400 ) ) +#endif + + +static const value_string ccsds_primary_header_sequence_flags[] = { + { 0, "Continuation segment" }, + { 1, "First segment" }, + { 2, "Last segment" }, + { 3, "Unsegmented data" }, + { 0, NULL } +}; + +static const value_string ccsds_secondary_header_type[] = { + { 0, "Core" }, + { 1, "Payload" }, + { 0, NULL } +}; + +static const value_string ccsds_secondary_header_packet_type[] = { + { 0, "UNDEFINED" }, + { 1, "Data Dump" }, + { 2, "UNDEFINED" }, + { 3, "UNDEFINED" }, + { 4, "TLM/Status" }, + { 5, "UNDEFINED" }, + { 6, "Payload Private/Science" }, + { 7, "Ancillary Data" }, + { 8, "Essential Cmd" }, + { 9, "System Cmd" }, + { 10, "Payload Cmd" }, + { 11, "Data Load/File Transfer" }, + { 12, "UNDEFINED" }, + { 13, "UNDEFINED" }, + { 14, "UNDEFINED" }, + { 15, "UNDEFINED" }, + { 0, NULL } +}; + +static const value_string ccsds_secondary_header_element_id[] = { + { 0, "NASA (Ground Test Only)" }, + { 1, "NASA" }, + { 2, "ESA/APM" }, + { 3, "NASDA" }, + { 4, "RSA" }, + { 5, "CSA" }, + { 6, "ESA/ATV" }, + { 7, "ASI" }, + { 8, "ESA/ERA" }, + { 9, "Reserved" }, + { 10, "RSA SPP" }, + { 11, "NASDA HTV" }, + { 12, "Reserved" }, + { 13, "Reserved" }, + { 14, "Reserved" }, + { 15, "Reserved" }, + { 0, NULL } +}; + +static const value_string ccsds_secondary_header_cmd_data_packet[] = { + { 0, "Command Packet" }, + { 1, "Data Packet" }, + { 0, NULL } +}; + +static const value_string ccsds_secondary_header_format_id[] = { + { 0, "Reserved" }, + { 1, "Essential Telemetry" }, + { 2, "Housekeeping Tlm - 1" }, + { 3, "Housekeeping Tlm - 2" }, + { 4, "PCS DDT" }, + { 5, "CCS S-Band Command Response" }, + { 6, "Contingency Telemetry via the SMCC" }, + { 7, "Normal Data Dump" }, + { 8, "Extended Data Dump" }, + { 9, "Reserved" }, + { 10, "Reserved" }, + { 11, "Broadcast Ancillary Data" }, + { 12, "Reserved" }, + { 13, "NCS to OIU Telemetry and ECOMM Telemetry" }, + { 14, "CCS to OIU Telemetry - Direct" }, + { 15, "Reserved" }, + { 16, "Normal File Dump" }, + { 17, "Extended File Dump" }, + { 18, "NCS to FGB Telemetry" }, + { 19, "Reserved" }, + { 20, "ZOE Normal Dump (S-Band)" }, + { 21, "ZOE Extended Dump (S-Band)" }, + { 22, "EMU S-Band TLM Packet" }, + { 23, "Reserved" }, + { 24, "Reserved" }, + { 25, "Reserved" }, + { 26, "CCS to OIU Telemetry via UHF" }, + { 27, "OSTP Telemetry (After Flight 1E, CCS R5)" }, + { 28, "Reserved" }, + { 29, "Reserved" }, + { 30, "Reserved" }, + { 31, "Reserved" }, + { 32, "Reserved" }, + { 33, "Reserved" }, + { 34, "Reserved" }, + { 35, "Reserved" }, + { 36, "Reserved" }, + { 37, "Reserved" }, + { 38, "Reserved" }, + { 39, "Reserved" }, + { 40, "Reserved" }, + { 41, "Reserved" }, + { 42, "Reserved" }, + { 43, "Reserved" }, + { 44, "Reserved" }, + { 45, "Reserved" }, + { 46, "Reserved" }, + { 47, "Reserved" }, + { 48, "Reserved" }, + { 49, "Reserved" }, + { 50, "Reserved" }, + { 51, "Reserved" }, + { 52, "Reserved" }, + { 53, "Reserved" }, + { 54, "Reserved" }, + { 55, "Reserved" }, + { 56, "Reserved" }, + { 57, "Reserved" }, + { 58, "Reserved" }, + { 59, "Reserved" }, + { 60, "Reserved" }, + { 61, "Reserved" }, + { 62, "Reserved" }, + { 63, "Reserved" }, + { 0, NULL } +}; + + + + +/* convert time from utc to julian values */ +void utc_to_julian ( int utc, int* year, int* julianday, int* hour, int* minute, int* second ) +{ + static int Days[2][13] = + { + { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } + }; + + int j, days_yr[2], left, secs; + + /* oops... */ + if ( ! year || ! julianday || ! hour || ! minute || ! second ) return; + + *year = 1970; + *julianday = 0; + *hour = 0; + *minute = 0; + *second = 0; + + days_yr[0] = days_yr[1] = 0; + + for ( j=1; j < 13; ++j ) + { + days_yr[0] += Days[0][j]; + days_yr[1] += Days[1][j]; + } + + left = utc; + secs = days_yr[Leap(*year)] * 24 * 60 * 60; + + while (left > secs) + { + ++(*year); + left -= secs; + secs = days_yr[Leap(*year)] * 24 * 60 * 60; + } + + *julianday = (left / (24 * 60 * 60)) + 1; + left = left % (24 * 60 * 60); + + *hour = left / (60 * 60); + left = left % (60 * 60); + + *minute = left / 60; + + *second = left % 60; + +} + + + +/* convert ccsds embedded time to a human readable string - NOT THREAD SAFE */ +static const char* embedded_time_to_string ( int coarse_time, int fine_time ) +{ + static const char* fmt = "%04d/%03d:%02d:%02d:%02d.%03d"; + static char juliantime[40]; + static int utcdiff = 0; + + int utc, yr, year, julianday, hour, minute, second, fraction; + int multiplier = 1000; + + /* compute the static constant difference in seconds + * between midnight 5-6 January 1980 (GPS time) and + * seconds since 1/1/1970 (UTC time) just this once + */ + if ( 0 == utcdiff ) + { + for ( yr=1970; yr < 1980; ++yr ) + { + utcdiff += ( Leap(yr) ? 366 : 365 ) * 24 * 60 * 60; + } + + utcdiff += 5 * 24 * 60 * 60; /* five days of January 1980 */ + } + + utc = coarse_time + utcdiff; + utc_to_julian ( utc, &year, &julianday, &hour, &minute, &second ); + + fraction = ( multiplier * ( (int)fine_time & 0xff ) ) / 256; + + g_snprintf ( juliantime, sizeof(juliantime), fmt, year, julianday, hour, minute, second, fraction ); + + return juliantime; + +} + + /* Code to actually dissect the packets */ static void dissect_ccsds(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { int offset = 0; - proto_item *ti; + proto_item *ccsds_packet; proto_tree *ccsds_tree; - proto_item *header; - proto_tree *header_tree; + proto_item *primary_header; + proto_tree *primary_header_tree; guint16 first_word; - proto_item *header2; - proto_tree *header2_tree; - + guint32 coarse_time; + guint8 fine_time; + proto_item *secondary_header; + proto_tree *secondary_header_tree; + const char* time_string; + if (check_col(pinfo->cinfo, COL_PROTOCOL)) col_set_str(pinfo->cinfo, COL_PROTOCOL, "CCSDS"); if (check_col(pinfo->cinfo, COL_INFO)) col_set_str(pinfo->cinfo, COL_INFO, "CCSDS Packet"); if (tree) { - ti = proto_tree_add_item(tree, proto_ccsds, tvb, 0, -1, FALSE); - ccsds_tree = proto_item_add_subtree(ti, ett_ccsds); + ccsds_packet = proto_tree_add_item(tree, proto_ccsds, tvb, 0, -1, FALSE); + ccsds_tree = proto_item_add_subtree(ccsds_packet, ett_ccsds); + + /* build the ccsds primary header tree */ + primary_header=proto_tree_add_text(ccsds_tree, tvb, offset, CCSDS_PRIMARY_HEADER_LENGTH, "Primary CCSDS Header"); + primary_header_tree=proto_item_add_subtree(primary_header, ett_ccsds_primary_header); - header=proto_tree_add_text(ccsds_tree, tvb, 0, -1, - "Primary CCSDS Header"); - header_tree=proto_item_add_subtree(header, ett_header); - first_word=tvb_get_ntohs(tvb, offset); - proto_tree_add_uint(header_tree, hf_ccsds_version, tvb, offset, 2, first_word); - proto_tree_add_uint(header_tree, hf_ccsds_type, tvb, offset, 2, first_word); - proto_tree_add_boolean(header_tree, hf_ccsds_secheader, tvb, offset, 2, first_word); - proto_tree_add_uint(header_tree, hf_ccsds_apid, tvb, offset, 2, first_word); + proto_tree_add_uint(primary_header_tree, hf_ccsds_version, tvb, offset, 2, first_word); + proto_tree_add_uint(primary_header_tree, hf_ccsds_type, tvb, offset, 2, first_word); + proto_tree_add_boolean(primary_header_tree, hf_ccsds_secheader, tvb, offset, 2, first_word); + proto_tree_add_uint(primary_header_tree, hf_ccsds_apid, tvb, offset, 2, first_word); offset += 2; - proto_tree_add_item(header_tree, hf_ccsds_seqflag, tvb, offset, 2, FALSE); - proto_tree_add_item(header_tree, hf_ccsds_seqnum, tvb, offset, 2, FALSE); + proto_tree_add_item(primary_header_tree, hf_ccsds_seqflag, tvb, offset, 2, FALSE); + proto_tree_add_item(primary_header_tree, hf_ccsds_seqnum, tvb, offset, 2, FALSE); offset += 2; - proto_tree_add_item(header_tree, hf_ccsds_length, tvb, offset, 2, FALSE); + proto_tree_add_item(primary_header_tree, hf_ccsds_length, tvb, offset, 2, FALSE); offset += 2; - proto_item_set_end(header, tvb, offset); + proto_item_set_end(primary_header, tvb, offset); - if(first_word&HDR_SECHDR) + /* build the ccsds secondary header tree */ + if ( first_word & HDR_SECHDR ) { - header2=proto_tree_add_text(ccsds_tree, tvb, offset, -1, - "Secondary CCSDS Header"); - header2_tree=proto_item_add_subtree(header2, ett_header2); + secondary_header=proto_tree_add_text(ccsds_tree, tvb, offset, CCSDS_SECONDARY_HEADER_LENGTH, "Secondary CCSDS Header"); + secondary_header_tree=proto_item_add_subtree(secondary_header, ett_ccsds_secondary_header); - proto_tree_add_item(header2_tree, hf_ccsds_time, tvb, offset, 5, FALSE); - offset += 5; + /* command ccsds secondary header flags */ + coarse_time=tvb_get_ntohl(tvb, offset); + proto_tree_add_item(secondary_header_tree, hf_ccsds_coarse_time, tvb, offset, 4, FALSE); + offset += 4; - proto_tree_add_item(header2_tree, hf_ccsds_timeid, tvb, offset, 1, FALSE); - proto_tree_add_item(header2_tree, hf_ccsds_checkword, tvb, offset, 1, FALSE); - proto_tree_add_item(header2_tree, hf_ccsds_zoe, tvb, offset, 1, FALSE); - proto_tree_add_item(header2_tree, hf_ccsds_packtype, tvb, offset, 1, FALSE); - offset += 1; + fine_time=tvb_get_guint8(tvb, offset); + proto_tree_add_item(secondary_header_tree, hf_ccsds_fine_time, tvb, offset, 1, FALSE); + ++offset; - proto_tree_add_item(header2_tree, hf_ccsds_vid, tvb, offset, 2, FALSE); - offset += 2; + time_string = embedded_time_to_string ( coarse_time, fine_time ); + proto_tree_add_text(secondary_header_tree, tvb, offset-5, 5, "%s = Embedded Time", time_string); - proto_tree_add_item(header2_tree, hf_ccsds_dcc, tvb, offset, 2, FALSE); - offset += 2; - proto_item_set_end(header2, tvb, offset); + proto_tree_add_item(secondary_header_tree, hf_ccsds_timeid, tvb, offset, 1, FALSE); + proto_tree_add_item(secondary_header_tree, hf_ccsds_checkword, tvb, offset, 1, FALSE); + + /* payload specific ccsds secondary header flags */ + if ( first_word & HDR_TYPE ) + { + proto_tree_add_item(secondary_header_tree, hf_ccsds_zoe, tvb, offset, 1, FALSE); + proto_tree_add_item(secondary_header_tree, hf_ccsds_packet_type_unused, tvb, offset, 1, FALSE); + ++offset; + + proto_tree_add_item(secondary_header_tree, hf_ccsds_vid, tvb, offset, 2, FALSE); + offset += 2; + + proto_tree_add_item(secondary_header_tree, hf_ccsds_dcc, tvb, offset, 2, FALSE); + offset += 2; + } + + /* core specific ccsds secondary header flags */ + else + { + /* proto_tree_add_item(secondary_header_tree, hf_ccsds_spare1, tvb, offset, 1, FALSE); */ + proto_tree_add_item(secondary_header_tree, hf_ccsds_packet_type, tvb, offset, 1, FALSE); + ++offset; + + /* proto_tree_add_item(secondary_header_tree, hf_ccsds_spare2, tvb, offset, 2, FALSE); */ + proto_tree_add_item(secondary_header_tree, hf_ccsds_element_id, tvb, offset, 2, FALSE); + proto_tree_add_item(secondary_header_tree, hf_ccsds_cmd_data_packet, tvb, offset, 2, FALSE); + proto_tree_add_item(secondary_header_tree, hf_ccsds_format_version_id, tvb, offset, 2, FALSE); + proto_tree_add_item(secondary_header_tree, hf_ccsds_extended_format_id, tvb, offset, 2, FALSE); + offset += 2; + + /* proto_tree_add_item(secondary_header_tree, hf_ccsds_spare3, tvb, offset, 1, FALSE); */ + ++offset; + + proto_tree_add_item(secondary_header_tree, hf_ccsds_frame_id, tvb, offset, 1, FALSE); + ++offset; + } + + /* finish the ccsds secondary header */ + proto_item_set_end(secondary_header, tvb, offset); } - proto_tree_add_text(ccsds_tree, tvb, offset, -1, - "Data"); + /* everything that's left is the remainder of the packet data zone */ + proto_tree_add_text(ccsds_tree, tvb, offset, -1, "Data"); } } -/* Register the protocol with Wireshark */ -/* this format is require because a script is used to build the C function - that calls all the protocol registration. -*/ +/* Register the protocol with Wireshark + * this format is require because a script is used to build the C function + * that calls all the protocol registration. + */ void proto_register_ccsds(void) { - + /* Setup list of header fields See Section 1.6.1 for details*/ static hf_register_info hf[] = { + + /* primary ccsds header flags */ { &hf_ccsds_version, - { "version", "ccsds.version", + { "Version", "ccsds.version", FT_UINT16, BASE_DEC, NULL, HDR_VERSION, - "version", HFILL } + NULL, HFILL } }, { &hf_ccsds_type, - { "type", "ccsds.type", - FT_UINT16, BASE_DEC, NULL, HDR_TYPE, - "type", HFILL } + { "Type", "ccsds.type", + FT_UINT16, BASE_DEC, VALS(ccsds_secondary_header_type), HDR_TYPE, + NULL, HFILL } }, { &hf_ccsds_secheader, - { "secondary header", "ccsds.secheader", + { "Secondary Header", "ccsds.secheader", FT_BOOLEAN, 16, NULL, HDR_SECHDR, - "secondary header present", HFILL } + "Secondary Header Present", HFILL } }, { &hf_ccsds_apid, { "APID", "ccsds.apid", FT_UINT16, BASE_DEC, NULL, HDR_APID, - "Represents APID", HFILL } + NULL, HFILL } }, { &hf_ccsds_seqflag, - { "sequence flags", "ccsds.seqflag", - FT_UINT16, BASE_DEC, NULL, 0xc000, - "sequence flags", HFILL } + { "Sequence Flags", "ccsds.seqflag", + FT_UINT16, BASE_DEC, VALS(ccsds_primary_header_sequence_flags), 0xc000, + NULL, HFILL } }, { &hf_ccsds_seqnum, - { "sequence number", "ccsds.seqnum", + { "Sequence Number", "ccsds.seqnum", FT_UINT16, BASE_DEC, NULL, 0x3fff, - "sequence number", HFILL } + NULL, HFILL } }, { &hf_ccsds_length, - { "packet length", "ccsds.length", + { "Packet Length", "ccsds.length", FT_UINT16, BASE_DEC, NULL, 0xffff, - "packet length", HFILL } + NULL, HFILL } + }, + + + /* common ccsds secondary header flags */ + { &hf_ccsds_coarse_time, + { "Coarse Time", "ccsds.coarse_time", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } }, - { &hf_ccsds_time, - { "time", "ccsds.time", - FT_BYTES, BASE_HEX, NULL, 0x0, - "time", HFILL } + { &hf_ccsds_fine_time, + { "Fine Time", "ccsds.fine_time", + FT_UINT8, BASE_DEC, NULL, 0xff, + NULL, HFILL } }, { &hf_ccsds_timeid, - { "time identifier", "ccsds.timeid", - FT_UINT8, BASE_DEC, NULL, 0xC0, - "time identifier", HFILL } + { "Time Identifier", "ccsds.timeid", + FT_UINT8, BASE_DEC, NULL, 0xc0, + NULL, HFILL } }, { &hf_ccsds_checkword, - { "checkword indicator", "ccsds.checkword", + { "Checkword Indicator", "ccsds.checkword", FT_UINT8, BASE_DEC, NULL, 0x20, - "checkword indicator", HFILL } + NULL, HFILL } }, + + + /* payload specific ccsds secondary header flags */ { &hf_ccsds_zoe, { "ZOE TLM", "ccsds.zoe", FT_UINT8, BASE_DEC, NULL, 0x10, - "CONTAINS S-BAND ZOE PACKETS", HFILL } + "Contains S-band ZOE Packets", HFILL } }, - { &hf_ccsds_packtype, - { "packet type", "ccsds.packtype", + { &hf_ccsds_packet_type_unused, + { "Packet Type (unused for Ku-band)", "ccsds.packet_type", FT_UINT8, BASE_DEC, NULL, 0x0f, - "Packet Type - Unused in Ku-Band", HFILL } + NULL, HFILL } }, { &hf_ccsds_vid, - { "version identifier", "ccsds.vid", + { "Version Identifier", "ccsds.vid", FT_UINT16, BASE_DEC, NULL, 0x0, - "version identifier", HFILL } + NULL, HFILL } }, { &hf_ccsds_dcc, { "Data Cycle Counter", "ccsds.dcc", FT_UINT16, BASE_DEC, NULL, 0x0, - "Data Cycle Counter", HFILL } + NULL, HFILL } + }, + + + /* core specific ccsds secondary header flags */ + { &hf_ccsds_spare1, + { "Spare Bit 1", "ccsds.spare1", + FT_UINT8, BASE_DEC, NULL, 0x10, + "unused spare bit 1", HFILL } + }, + { &hf_ccsds_packet_type, + { "Packet Type", "ccsds.packet_type", + FT_UINT8, BASE_DEC, VALS(ccsds_secondary_header_packet_type), 0x0f, + NULL, HFILL } + }, + { &hf_ccsds_spare2, + { "Spare Bit 2", "ccsds.spare2", + FT_UINT16, BASE_DEC, NULL, 0x8000, + NULL, HFILL } }, + { &hf_ccsds_element_id, + { "Element ID", "ccsds.element_id", + FT_UINT16, BASE_DEC, VALS(ccsds_secondary_header_element_id), 0x7800, + NULL, HFILL } + }, + { &hf_ccsds_cmd_data_packet, + { "Cmd/Data Packet Indicator", "ccsds.cmd_data_packet", + FT_UINT16, BASE_DEC, VALS(ccsds_secondary_header_cmd_data_packet), 0x0400, + NULL, HFILL } + }, + { &hf_ccsds_format_version_id, + { "Format Version ID", "ccsds.format_version_id", + FT_UINT16, BASE_DEC, NULL, 0x03c0, + NULL, HFILL } + }, + { &hf_ccsds_extended_format_id, + { "Extended Format ID", "ccsds.extended_format_id", + FT_UINT16, BASE_DEC, VALS(ccsds_secondary_header_format_id), 0x003f, + NULL, HFILL } + }, + { &hf_ccsds_spare3, + { "Spare Bits 3", "ccsds.spare3", + FT_UINT8, BASE_DEC, NULL, 0xff, + NULL, HFILL } + }, + { &hf_ccsds_frame_id, + { "Frame ID", "ccsds.frame_id", + FT_UINT8, BASE_DEC, NULL, 0xff, + NULL, HFILL } + }, + }; -/* Setup protocol subtree array */ + /* Setup protocol subtree array */ static gint *ett[] = { &ett_ccsds, - &ett_header, - &ett_header2, + &ett_ccsds_primary_header, + &ett_ccsds_secondary_header }; -/* Register the protocol name and description */ + /* Register the protocol name and description */ proto_ccsds = proto_register_protocol("CCSDS", "CCSDS", "ccsds"); -/* Required function calls to register the header fields and subtrees used */ + /* Required function calls to register the header fields and subtrees used */ proto_register_field_array(proto_ccsds, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); - register_dissector("ccsds", dissect_ccsds, proto_ccsds); } /* If this dissector uses sub-dissector registration add a registration routine. - This format is required because a script is used to find these routines and - create the code that calls these routines. -*/ + * This format is required because a script is used to find these routines and + * create the code that calls these routines. + */ void proto_reg_handoff_ccsds(void) { - dissector_handle_t ccsds_handle; - - ccsds_handle = create_dissector_handle(dissect_ccsds, - proto_ccsds); - dissector_add_handle("udp.port", ccsds_handle); + register_dissector ( "ccsds", dissect_ccsds, proto_ccsds ); + dissector_add ( "udp.port", 0, find_dissector("ccsds") ); } + diff --git a/epan/dissectors/packet-ehs.c b/epan/dissectors/packet-ehs.c new file mode 100644 index 0000000000..2719b01d18 --- /dev/null +++ b/epan/dissectors/packet-ehs.c @@ -0,0 +1,1924 @@ +/* packet-vcdu.c + * Routines for VCDU dissection + * Copyright 2000, Scott Hovis scott.hovis@ums.msfc.nasa.gov + * Enhanced 2008, Matt Dunkle Matthew.L.Dunkle@nasa.gov + * + * $Id$ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.com> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <glib.h> +#include <epan/packet.h> + + +/* Initialize the protocol and registered fields */ +static int proto_ehs = -1; + +static int hf_ehs_ph_version = -1; +static int hf_ehs_ph_project = -1; +static int hf_ehs_ph_support_mode = -1; +static int hf_ehs_ph_data_mode = -1; +static int hf_ehs_ph_mission = -1; +static int hf_ehs_ph_protocol = -1; + +static int hf_ehs_ph_year = -1; /* numeric year as years since 1900 */ +static int hf_ehs_ph_jday = -1; /* julian day of year */ +static int hf_ehs_ph_hour = -1; +static int hf_ehs_ph_minute = -1; +static int hf_ehs_ph_second = -1; +static int hf_ehs_ph_tenths = -1; + +static int hf_ehs_ph_new_data_flag = -1; /* indicates the time has changed */ +static int hf_ehs_ph_pad1 = -1; +static int hf_ehs_ph_hold_flag = -1; /* indicates a hold condition */ +static int hf_ehs_ph_sign_flag = -1; /* indicates pre-mission, i.e. countdown, time */ + +static int hf_ehs_ph_pad2 = -1; +static int hf_ehs_ph_pad3 = -1; +static int hf_ehs_ph_pad4 = -1; + +static int hf_ehs_ph_hosc_packet_size = -1; + +/* generic ehs secondary header values */ +static int hf_ehs_sh_version = -1; +static int hf_ehs_sh_data_status_bit_5 = -1; +static int hf_ehs_sh_data_status_bit_4 = -1; +static int hf_ehs_sh_data_status_bit_3 = -1; +static int hf_ehs_sh_data_status_bit_2 = -1; +static int hf_ehs_sh_data_status_bit_1 = -1; +static int hf_ehs_sh_data_status_bit_0 = -1; + +/* other common remappings of the data status bits specific to certain secondary ehs header values */ +static int hf_ehs_sh_parent_stream_error = -1; /* data status bit 3 */ +static int hf_ehs_sh_vcdu_sequence_error = -1; /* data status bit 2 */ +static int hf_ehs_sh_packet_sequence_error = -1; /* data status bit 1 */ + +/* common ehs secondary header values */ +static int hf_ehs_sh_vcdu_sequence_number = -1; +static int hf_ehs_sh_data_stream_id = -1; +static int hf_ehs_sh_pdss_reserved_1 = -1; +static int hf_ehs_sh_pdss_reserved_2 = -1; +static int hf_ehs_sh_pdss_reserved_3 = -1; +static int hf_ehs_sh_gse_pkt_id = -1; +static int hf_ehs_sh_payload_vs_core_id = -1; +static int hf_ehs_sh_apid = -1; +static int hf_ehs_sh_virtual_channel = -1; +static int hf_ehs_sh_pdss_reserved_sync = -1; + +/* tdm ehs secondary header values */ +static int hf_ehs_sh_tdm_secondary_header_length = -1; + +static int hf_ehs_sh_tdm_extra_data_packet = -1; +static int hf_ehs_sh_tdm_backup_stream_id_number = -1; +static int hf_ehs_sh_tdm_end_of_data_flag = -1; +static int hf_ehs_sh_tdm_parent_frame_error = -1; +static int hf_ehs_sh_tdm_checksum_error = -1; +static int hf_ehs_sh_tdm_fixed_value_error = -1; + +static int hf_ehs_sh_tdm_minor_frame_counter_error = -1; +static int hf_ehs_sh_tdm_format_id_error = -1; +static int hf_ehs_sh_tdm_bit_slip_error = -1; +static int hf_ehs_sh_tdm_sync_error = -1; +static int hf_ehs_sh_tdm_aoslos_flag = -1; +static int hf_ehs_sh_tdm_override_errors_flag = -1; +static int hf_ehs_sh_tdm_data_status = -1; + +static int hf_ehs_sh_tdm_idq = -1; +static int hf_ehs_sh_tdm_cdq = -1; +static int hf_ehs_sh_tdm_adq = -1; +static int hf_ehs_sh_tdm_data_dq = -1; +static int hf_ehs_sh_tdm_unused = -1; +static int hf_ehs_sh_tdm_format_id = -1; + +static int hf_ehs_sh_tdm_major_frame_packet_index = -1; +static int hf_ehs_sh_tdm_numpkts_per_major_frame = -1; +static int hf_ehs_sh_tdm_num_minor_frames_per_packet = -1; + +static int hf_ehs_sh_tdm_cntmet_present = -1; +static int hf_ehs_sh_tdm_obt_present = -1; +static int hf_ehs_sh_tdm_major_frame_status_present = -1; +static int hf_ehs_sh_tdm_reserved = -1; + +static int hf_ehs_sh_tdm_cnt_year = -1; /* numeric year as years since 1900 */ +static int hf_ehs_sh_tdm_cnt_jday = -1; /* julian day of year */ +static int hf_ehs_sh_tdm_cnt_hour = -1; +static int hf_ehs_sh_tdm_cnt_minute = -1; +static int hf_ehs_sh_tdm_cnt_second = -1; +static int hf_ehs_sh_tdm_cnt_tenths = -1; + +static int hf_ehs_sh_tdm_obt_year = -1; /* numeric year as years since 1900 */ +static int hf_ehs_sh_tdm_obt_jday = -1; /* julian day of year */ +static int hf_ehs_sh_tdm_obt_hour = -1; +static int hf_ehs_sh_tdm_obt_minute = -1; +static int hf_ehs_sh_tdm_obt_second = -1; +static int hf_ehs_sh_tdm_obt_tenths = -1; + +static int hf_ehs_sh_tdm_obt_delta_time_flag = -1; +static int hf_ehs_sh_tdm_obt_computed_flag = -1; +static int hf_ehs_sh_tdm_obt_not_retrieved_flag = -1; +static int hf_ehs_sh_tdm_obt_reserved = -1; +static int hf_ehs_sh_tdm_obt_source_apid = -1; + +static int hf_ehs_sh_tdm_num_major_frame_status_words = -1; + +static int hf_ehs_sh_tdm_mjfs_reserved = -1; +static int hf_ehs_sh_tdm_mjfs_parent_frame_error = -1; +static int hf_ehs_sh_tdm_mjfs_checksum_error = -1; +static int hf_ehs_sh_tdm_mjfs_fixed_value_error = -1; + +static int hf_ehs_sh_tdm_mnfs_parent_frame_error = -1; +static int hf_ehs_sh_tdm_mnfs_data_not_available = -1; +static int hf_ehs_sh_tdm_mnfs_checksum_error = -1; +static int hf_ehs_sh_tdm_mnfs_fixed_value_error = -1; +static int hf_ehs_sh_tdm_mnfs_counter_error = -1; +static int hf_ehs_sh_tdm_mnfs_format_id_error = -1; +static int hf_ehs_sh_tdm_mnfs_bit_slip_error = -1; +static int hf_ehs_sh_tdm_mnfs_sync_error = -1; + +/* pseudo ehs secondary header values */ +static int hf_ehs_sh_pseudo_unused = -1; +static int hf_ehs_sh_pseudo_workstation_id = -1; +static int hf_ehs_sh_pseudo_user_id = -1; +static int hf_ehs_sh_pseudo_comp_id = -1; + +/* data zone values for well known protocol AOS/LOS */ +static int hf_ehs_dz_aoslos_indicator = -1; + +/* data zone values for well known protocol UDSM */ +static int hf_ehs_dz_udsm_ccsds_vs_bpdu = -1; +static int hf_ehs_dz_udsm_unused1 = -1; + +static int hf_ehs_dz_udsm_unused2 = -1; + +static int hf_ehs_dz_udsm_unused3 = -1; +static int hf_ehs_dz_udsm_gse_pkt_id = -1; +static int hf_ehs_dz_udsm_payload_vs_core = -1; +static int hf_ehs_dz_udsm_apid = -1; + +static int hf_ehs_dz_udsm_start_time_year = -1; +static int hf_ehs_dz_udsm_start_time_jday = -1; +static int hf_ehs_dz_udsm_start_time_hour = -1; +static int hf_ehs_dz_udsm_start_time_minute = -1; +static int hf_ehs_dz_udsm_start_time_second = -1; + +static int hf_ehs_dz_udsm_stop_time_year = -1; +static int hf_ehs_dz_udsm_stop_time_jday = -1; +static int hf_ehs_dz_udsm_stop_time_hour = -1; +static int hf_ehs_dz_udsm_stop_time_minute = -1; +static int hf_ehs_dz_udsm_stop_time_second = -1; + +static int hf_ehs_dz_udsm_unused4 = -1; + +static int hf_ehs_dz_udsm_num_pkts_xmtd = -1; + +static int hf_ehs_dz_udsm_num_vcdu_seqerrs = -1; + +static int hf_ehs_dz_udsm_num_pkt_seqerrs = -1; + +static int hf_ehs_dz_udsm_num_pktlen_errors = -1; + +static int hf_ehs_dz_udsm_event = -1; + +static int hf_ehs_dz_udsm_num_pkts_xmtd_rollover = -1; + + +/* handle to ccsds packet dissector */ +static dissector_handle_t ccsds_handle = (dissector_handle_t)-1; + +/* Initialize the subtree pointers */ +static gint ett_ehs = -1; +static gint ett_ehs_primary_header = -1; +static gint ett_ehs_secondary_header = -1; +static gint ett_ehs_data_zone = -1; + +/* EHS protocol types */ +typedef enum EHS_Protocol_Type +{ + EHS_PROTOCOL__ALL_PROTOCOLS, + EHS_PROTOCOL__TDM_TELEMETRY, + EHS_PROTOCOL__NASCOM_TELEMETRY, + EHS_PROTOCOL__PSEUDO_TELEMETRY, + EHS_PROTOCOL__TDS_DATA, + EHS_PROTOCOL__TEST_DATA, + EHS_PROTOCOL__GSE_DATA, + EHS_PROTOCOL__CUSTOM_DATA, + EHS_PROTOCOL__HDRS_DQ, + EHS_PROTOCOL__CSS, + EHS_PROTOCOL__AOS_LOS, + EHS_PROTOCOL__PDSS_PAYLOAD_CCSDS_PACKET, + EHS_PROTOCOL__PDSS_CORE_CCSDS_PACKET, + EHS_PROTOCOL__PDSS_PAYLOAD_BPDU, + EHS_PROTOCOL__PDSS_UDSM, + EHS_PROTOCOL__PDSS_RPSM, + NUMBER_PROTOCOLS = 15 +} EHS_Protocol_Type_t; + + +/* some basic sizing parameters */ +enum +{ + IP_HEADER_LENGTH = 48, + CCSDS_PRIMARY_HEADER_LENGTH = 6, + CCSDS_SECONDARY_HEADER_LENGTH = 10, + EHS_PRIMARY_HEADER_SIZE = 16, + EHS_SECONDARY_HEADER_SIZE = 12 +}; + +/* determine if a ccsds primary header indicates a secondary exists */ +#define HDR_SECHDR 0x0800 + + +static const value_string ehs_primary_header_project[] = +{ + { 0, "All" }, + { 1, "STS" }, + { 2, "SL" }, + { 3, "ISS" }, + { 4, "AXAF" }, + { 0, NULL } +}; + +static const value_string ehs_primary_header_support_mode[] = +{ + { 0, "All" }, + { 1, "Flight" }, + { 2, "Test" }, + { 3, "Sim" }, + { 4, "Validation" }, + { 5, "Development" }, + { 6, "Training" }, + { 7, "Offline" }, + { 0, NULL } +}; + +static const value_string ehs_primary_header_data_mode[] = +{ + { 0, "Unused" }, + { 1, "Realtime" }, + { 2, "Dump1" }, + { 3, "Dump2" }, + { 4, "Dump3" }, + { 5, "Playback1" }, + { 6, "Playback2" }, + { 7, "Playback3" }, + { 8, "Playback4" }, + { 9, "Playback5" }, + { 10, "Playback6" }, + { 11, "Playback7" }, + { 12, "Playback8" }, + { 13, "Playback9" }, + { 14, "Playback10" }, + { 15, "Playback11" }, + { 16, "Mode Independent" }, + { 0, NULL } +}; + +static const value_string ehs_primary_header_protocol[] = +{ + { 0, "All" }, + { 1, "TDM" }, + { 2, "NASCOM" }, + { 3, "PSEUDO" }, + { 4, "Time" }, + { 5, "Test" }, + { 6, "GSE" }, + { 7, "Custom_Data" }, + { 8, "HDRS_DQ" }, + { 9, "CSS" }, + { 10, "AOS_LOS" }, + { 11, "PDSS_PAYLOAD_CCSDS" }, + { 12, "PDSS_CORE_CCSDS" }, + { 13, "PDSS_PAYLOAD_BPDU" }, + { 14, "PDSS_UDSM" }, + { 15, "PDSS_RPSM" }, + { 0, NULL } +}; + +static const value_string ehs_secondary_header_data_stream_id[] = +{ + { 0, "CCSDS" }, + { 1, "BPDU" }, + { 0, NULL } +}; + +static const value_string ehs_secondary_header_payload_vs_core_id[] = +{ + { 0, "Core" }, + { 1, "Payload" }, + { 0, NULL } +}; + +static const value_string ehs_secondary_header_tdm_backup_stream_id[] = +{ + { 0, "Stream A / KMTS-A" }, + { 1, "Stream B / KMTS-B" }, + { 2, "SKR" }, + { 0, NULL } +}; + +static const value_string ehs_secondary_header_tdm_end_of_data_flag[] = +{ + { 0, "OK" }, + { 1, "Loss of Clock" }, + { 2, "Watchdog Timeout" }, + { 3, "Loss of Sync" }, + { 0, NULL } +}; + +static const value_string ehs_secondary_header_tdm_aoslos_flag[] = +{ + { 0, "AOS" }, + { 1, "LOS" }, + { 0, NULL } +}; + +static const value_string ehs_secondary_header_tdm_data_status[] = +{ + { 0, "OK" }, + { 1, "Suspect" }, + { 2, "DQ Failed" }, + { 3, "No Data" }, + { 0, NULL } +}; + +static const value_string ehs_data_zone_aoslos_indicator[] = +{ + { 0, "S-band LOS" }, + { 1, "S-band AOS" }, + { 2, "Ku-band LOS" }, + { 3, "Ku-band AOS" }, + { 0, NULL } +}; + +static const value_string ehs_data_zone_udsm_ccsds_vs_bpdu[] = +{ + { 0, "CCSDS" }, + { 1, "BPDU" }, + { 0, NULL } +}; + +static const value_string ehs_data_zone_udsm_payload_vs_core[] = +{ + { 0, "Core" }, + { 1, "Payload" }, + { 0, NULL } +}; + +static const value_string ehs_data_zone_udsm_event[] = +{ + { 0, "Undefined" }, + { 1, "Actual LOS" }, + { 2, "Scheduled End of Data" }, + { 3, "Operator Requested" }, + { 0, NULL } +}; + + +/* function to return EHS secondary header size according to protocol. + * the buffer pointer tvb should be pointing to the packets ehs primary + * header, and the offset should be set to the start of the ehs secondary + * header on input. + */ +static int ehs_secondary_header_size ( int protocol, tvbuff_t* tvb, int offset ) +{ + /* for most protocols the ehs secondary header is a standard size */ + int size = EHS_SECONDARY_HEADER_SIZE; + + switch ( protocol ) + { + case EHS_PROTOCOL__TDM_TELEMETRY: + /* the TDM secondary header size is variable. it's value is actually + * contained in the first two bytes of the secondary header itself. + */ + size = tvb_get_ntohs ( tvb, offset ); + break; + + case EHS_PROTOCOL__NASCOM_TELEMETRY: + break; + + case EHS_PROTOCOL__PSEUDO_TELEMETRY: + size = 8; + break; + + case EHS_PROTOCOL__TDS_DATA: + break; + + case EHS_PROTOCOL__TEST_DATA: + break; + + case EHS_PROTOCOL__GSE_DATA: + size = 16; + break; + + case EHS_PROTOCOL__CUSTOM_DATA: + break; + + case EHS_PROTOCOL__HDRS_DQ: + break; + + case EHS_PROTOCOL__CSS: + break; + + case EHS_PROTOCOL__AOS_LOS: + break; + + case EHS_PROTOCOL__PDSS_PAYLOAD_CCSDS_PACKET: + break; + + case EHS_PROTOCOL__PDSS_CORE_CCSDS_PACKET: + break; + + case EHS_PROTOCOL__PDSS_PAYLOAD_BPDU: + break; + + case EHS_PROTOCOL__PDSS_UDSM: + break; + + case EHS_PROTOCOL__PDSS_RPSM: + break; + + default: + break; + } + + return size; + +} + + +/* common EHS secondary header dissector */ +static void common_secondary_header_dissector ( proto_tree* ehs_secondary_header_tree, tvbuff_t* tvb, int* offset ) +{ + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_vcdu_sequence_number, tvb, *offset, 3, FALSE ); + *offset += 3; + + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_data_stream_id, tvb, *offset, 1, FALSE ); + /* proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_pdss_reserved_1, tvb, *offset, 1, FALSE ); */ + ++(*offset); + + /* proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_pdss_reserved_2, tvb, *offset, 1, FALSE ); */ + ++(*offset); + + /* proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_pdss_reserved_3, tvb, *offset, 2, FALSE ); */ + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_gse_pkt_id, tvb, *offset, 2, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_payload_vs_core_id, tvb, *offset, 2, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_apid, tvb, *offset, 2, FALSE ); + *offset += 2; + + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_virtual_channel, tvb, *offset, 2, FALSE ); + *offset += 2; + + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_pdss_reserved_sync, tvb, *offset, 2, FALSE ); + *offset += 2; + +} + + +/* AOS/LOS EHS secondary header dissector */ +static void aoslos_secondary_header_dissector ( proto_tree* ehs_secondary_header_tree, tvbuff_t* tvb, int* offset ) +{ + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_version, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_data_status_bit_5, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_data_status_bit_4, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_data_status_bit_3, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_data_status_bit_2, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_data_status_bit_1, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_data_status_bit_0, tvb, *offset, 1, FALSE ); + ++(*offset); + + common_secondary_header_dissector ( ehs_secondary_header_tree, tvb, offset ); +} + + +/* payload ccsds secondary header dissector */ +static void payload_ccsds_secondary_header_dissector ( proto_tree* ehs_secondary_header_tree, tvbuff_t* tvb, int* offset ) +{ + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_version, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_data_status_bit_5, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_data_status_bit_4, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_data_status_bit_3, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_vcdu_sequence_error, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_packet_sequence_error, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_data_status_bit_0, tvb, *offset, 1, FALSE ); + ++(*offset); + + common_secondary_header_dissector ( ehs_secondary_header_tree, tvb, offset ); +} + + +/* core ccsds secondary header dissector */ +static void core_ccsds_secondary_header_dissector ( proto_tree* ehs_secondary_header_tree, tvbuff_t* tvb, int* offset ) +{ + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_version, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_data_status_bit_5, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_data_status_bit_4, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_parent_stream_error, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_vcdu_sequence_error, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_packet_sequence_error, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_data_status_bit_0, tvb, *offset, 1, FALSE ); + ++(*offset); + + common_secondary_header_dissector ( ehs_secondary_header_tree, tvb, offset ); +} + + +/* payload bpdu secondary header dissector */ +static void payload_bpdu_secondary_header_dissector ( proto_tree* ehs_secondary_header_tree, tvbuff_t* tvb, int* offset ) +{ + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_version, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_data_status_bit_5, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_data_status_bit_4, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_data_status_bit_3, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_vcdu_sequence_error, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_data_status_bit_1, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_data_status_bit_0, tvb, *offset, 1, FALSE ); + ++(*offset); + + common_secondary_header_dissector ( ehs_secondary_header_tree, tvb, offset ); +} + + +/* udsm secondary header dissector */ +static void udsm_secondary_header_dissector ( proto_tree* ehs_secondary_header_tree, tvbuff_t* tvb, int* offset ) +{ + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_version, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_data_status_bit_5, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_data_status_bit_4, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_data_status_bit_3, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_data_status_bit_2, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_data_status_bit_1, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_data_status_bit_0, tvb, *offset, 1, FALSE ); + ++(*offset); + + common_secondary_header_dissector ( ehs_secondary_header_tree, tvb, offset ); +} + + +/* tdm secondary header dissector */ +static void tdm_secondary_header_dissector ( proto_tree* ehs_secondary_header_tree, tvbuff_t* tvb, int* offset ) +{ + int j; + int num_major_frames = 0; + int num_minor_frames = 0; + int cntmet_present = 0; + int obt_present = 0; + int mjfs_present = 0; + + int year, jday, hour, minute, second, tenths; + + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_secondary_header_length, tvb, *offset, 2, FALSE ); + *offset += 2; + + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_extra_data_packet, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_backup_stream_id_number, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_end_of_data_flag, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_parent_frame_error, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_checksum_error, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_fixed_value_error, tvb, *offset, 1, FALSE ); + ++(*offset); + + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_minor_frame_counter_error, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_format_id_error, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_bit_slip_error, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_sync_error, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_aoslos_flag, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_override_errors_flag, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_data_status, tvb, *offset, 1, FALSE ); + ++(*offset); + + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_idq, tvb, *offset, 2, FALSE ); + *offset += 2; + + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_cdq, tvb, *offset, 2, FALSE ); + *offset += 2; + + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_adq, tvb, *offset, 2, FALSE ); + *offset += 2; + + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_data_dq, tvb, *offset, 2, FALSE ); + *offset += 2; + + /* proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_unused, tvb, *offset, 2, FALSE ); */ + *offset += 2; + + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_format_id, tvb, *offset, 2, FALSE ); + *offset += 2; + + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_major_frame_packet_index, tvb, *offset, 1, FALSE ); + ++(*offset); + + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_numpkts_per_major_frame, tvb, *offset, 1, FALSE ); + ++(*offset); + + num_minor_frames = 1 + tvb_get_guint8 ( tvb, *offset ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_num_minor_frames_per_packet, tvb, *offset, 1, FALSE ); + ++(*offset); + + cntmet_present = tvb_get_guint8 ( tvb, *offset ) & 0x80; + obt_present = tvb_get_guint8 ( tvb, *offset ) & 0x40; + mjfs_present = tvb_get_guint8 ( tvb, *offset ) & 0x20; + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_cntmet_present, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_obt_present, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_major_frame_status_present, tvb, *offset, 1, FALSE ); + /* proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_reserved, tvb, *offset, 1, FALSE ); */ + ++(*offset); + + if ( cntmet_present ) + { + year = tvb_get_guint8 ( tvb, *offset ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_cnt_year, tvb, *offset, 1, FALSE ); + ++(*offset); + + jday = tvb_get_ntohs ( tvb, *offset ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_cnt_jday, tvb, *offset, 2, FALSE ); + *offset += 2; + + hour = tvb_get_guint8 ( tvb, *offset ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_cnt_hour, tvb, *offset, 1, FALSE ); + ++(*offset); + + minute = tvb_get_guint8 ( tvb, *offset ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_cnt_minute, tvb, *offset, 1, FALSE ); + ++(*offset); + + second = tvb_get_guint8 ( tvb, *offset ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_cnt_second, tvb, *offset, 1, FALSE ); + ++(*offset); + + tenths = tvb_get_guint8 ( tvb, *offset ) >> 4; + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_cnt_tenths, tvb, *offset, 1, FALSE ); + ++(*offset); + + /* format a more readable time */ + proto_tree_add_text ( ehs_secondary_header_tree, tvb, *offset-7, 7, + "%04d/%03d:%02d:%02d:%02d.%1d = CNT/MET Time", year + 1900, jday, hour, minute, second, tenths ); + } + + + if ( obt_present ) + { + year = tvb_get_guint8 ( tvb, *offset ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_obt_year, tvb, *offset, 1, FALSE ); + ++(*offset); + + jday = tvb_get_ntohs ( tvb, *offset ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_obt_jday, tvb, *offset, 2, FALSE ); + *offset += 2; + + hour = tvb_get_guint8 ( tvb, *offset ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_obt_hour, tvb, *offset, 1, FALSE ); + ++(*offset); + + minute = tvb_get_guint8 ( tvb, *offset ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_obt_minute, tvb, *offset, 1, FALSE ); + ++(*offset); + + second = tvb_get_guint8 ( tvb, *offset ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_obt_second, tvb, *offset, 1, FALSE ); + ++(*offset); + + tenths = tvb_get_guint8 ( tvb, *offset ) >> 4; + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_obt_tenths, tvb, *offset, 1, FALSE ); + ++(*offset); + + /* format a more readable time */ + proto_tree_add_text ( ehs_secondary_header_tree, tvb, *offset-7, 7, + "%04d/%03d:%02d:%02d:%02d.%1d = OBT Time", year + 1900, jday, hour, minute, second, tenths ); + + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_obt_delta_time_flag, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_obt_computed_flag, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_obt_not_retrieved_flag, tvb, *offset, 1, FALSE ); + /* proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_obt_reserved, tvb, *offset, 1, FALSE ); */ + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_obt_source_apid, tvb, *offset, 1, FALSE ); + } + + if ( mjfs_present ) + { + proto_tree_add_text ( ehs_secondary_header_tree, tvb, *offset, 0, " " ); + + num_major_frames = 1 + tvb_get_guint8 ( tvb, *offset ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_num_major_frame_status_words, tvb, *offset, 1, FALSE ); + ++(*offset); + + for ( j=0; j < num_major_frames; ++j ) + { + proto_tree_add_text ( ehs_secondary_header_tree, tvb, *offset, 1, "Major Frame Status Byte# %d", j ); + /* proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_mjfs_reserved, tvb, *offset, 1, FALSE ); */ + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_mjfs_parent_frame_error, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_mjfs_checksum_error, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_mjfs_fixed_value_error, tvb, *offset, 1, FALSE ); + ++(*offset); + } + } + + proto_tree_add_text ( ehs_secondary_header_tree, tvb, *offset, 0, " " ); + + for ( j=0; j < num_minor_frames; ++j ) + { + proto_tree_add_text ( ehs_secondary_header_tree, tvb, *offset, 1, "Minor Frame Status Byte# %d", j ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_mnfs_parent_frame_error, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_mnfs_data_not_available, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_mnfs_checksum_error, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_mnfs_fixed_value_error, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_mnfs_counter_error, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_mnfs_format_id_error, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_mnfs_bit_slip_error, tvb, *offset, 1, FALSE ); + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_tdm_mnfs_sync_error, tvb, *offset, 1, FALSE ); + ++(*offset); + } + +} + + +/* pseudo secondary header dissector */ +static void pseudo_secondary_header_dissector ( proto_tree* ehs_secondary_header_tree, tvbuff_t* tvb, int* offset ) +{ + /* proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_pseudo_unused, tvb, *offset, 2, FALSE ); */ + *offset += 2; + + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_pseudo_workstation_id, tvb, *offset, 2, FALSE ); + *offset += 2; + + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_pseudo_user_id, tvb, *offset, 2, FALSE ); + *offset += 2; + + proto_tree_add_item ( ehs_secondary_header_tree, hf_ehs_sh_pseudo_comp_id, tvb, *offset, 2, FALSE ); + *offset += 2; + +} + + + + +/* EHS secondary header dissector */ +static void ehs_secondary_header_dissector ( int protocol, proto_tree* ehs_secondary_header_tree, tvbuff_t* tvb, int* offset ) +{ + /* the ehs secondary header structure is potentially different for each and every + * protocol type, including it's size. we support certain protocols but not all. + * for those protocols which are not supported we simply increment the offset + * and return. support for these other protocols can easily be added at a later + * time if and when it becomes necessary to do so. but for right now, we're only + * going to dissect those protocols that we work with on a regular basis in pdss. + */ + switch ( protocol ) + { + case EHS_PROTOCOL__TDM_TELEMETRY: + tdm_secondary_header_dissector ( ehs_secondary_header_tree, tvb, offset ); + break; + + case EHS_PROTOCOL__NASCOM_TELEMETRY: + *offset += ehs_secondary_header_size ( protocol, tvb, *offset ); + break; + + case EHS_PROTOCOL__PSEUDO_TELEMETRY: + pseudo_secondary_header_dissector ( ehs_secondary_header_tree, tvb, offset ); + break; + + case EHS_PROTOCOL__TDS_DATA: + *offset += ehs_secondary_header_size ( protocol, tvb, *offset ); + break; + + case EHS_PROTOCOL__TEST_DATA: + *offset += ehs_secondary_header_size ( protocol, tvb, *offset ); + break; + + case EHS_PROTOCOL__GSE_DATA: + *offset += ehs_secondary_header_size ( protocol, tvb, *offset ); + break; + + case EHS_PROTOCOL__CUSTOM_DATA: + *offset += ehs_secondary_header_size ( protocol, tvb, *offset ); + break; + + case EHS_PROTOCOL__HDRS_DQ: + *offset += ehs_secondary_header_size ( protocol, tvb, *offset ); + break; + + case EHS_PROTOCOL__CSS: + *offset += ehs_secondary_header_size ( protocol, tvb, *offset ); + break; + + case EHS_PROTOCOL__AOS_LOS: + aoslos_secondary_header_dissector ( ehs_secondary_header_tree, tvb, offset ); + break; + + case EHS_PROTOCOL__PDSS_PAYLOAD_CCSDS_PACKET: + payload_ccsds_secondary_header_dissector ( ehs_secondary_header_tree, tvb, offset ); + break; + + case EHS_PROTOCOL__PDSS_CORE_CCSDS_PACKET: + core_ccsds_secondary_header_dissector ( ehs_secondary_header_tree, tvb, offset ); + break; + + case EHS_PROTOCOL__PDSS_PAYLOAD_BPDU: + payload_bpdu_secondary_header_dissector ( ehs_secondary_header_tree, tvb, offset ); + break; + + case EHS_PROTOCOL__PDSS_UDSM: + udsm_secondary_header_dissector ( ehs_secondary_header_tree, tvb, offset ); + break; + + case EHS_PROTOCOL__PDSS_RPSM: + *offset += ehs_secondary_header_size ( protocol, tvb, *offset ); + break; + + default: + *offset += ehs_secondary_header_size ( protocol, tvb, *offset ); + break; + } +} + + +/* AOS/LOS data zone dissector */ +static void aoslos_data_zone_dissector ( proto_tree* ehs_tree, tvbuff_t* tvb, int* offset, packet_info* pinfo ) +{ + proto_item *ehs_data_zone; + proto_tree *ehs_data_zone_tree; + + /* create the data zone tree */ + ehs_data_zone = proto_tree_add_text ( ehs_tree, tvb, *offset, pinfo->iplen - IP_HEADER_LENGTH - *offset, "AOS/LOS Data Zone" ); + ehs_data_zone_tree = proto_item_add_subtree ( ehs_data_zone, ett_ehs_data_zone ); + + /* since the aos/los EHS packet data zone is well known, format it for display as well + * + * The AOS/LOS packet data zone is only 2 bytes in + * length and only 2 bits in the first byte are + * meaningful -- Ku band or S band and AOS or LOS + * + * 7-2 - unused + * 1-0 - band + AOS/LOS indicator + * + * bit 1 - 0=sband 1=kuband + * bit 0 - 0=LOS 1=AOS + * + * 0 00 - sband LOS + * 1 01 - sband AOS + * 2 10 - kuband LOS + * 3 11 - kuband AOS + */ + proto_tree_add_item ( ehs_data_zone_tree, hf_ehs_dz_aoslos_indicator, tvb, *offset, 1, FALSE ); + ++(*offset); +} + + +/* UDSM data zone dissector */ +static void udsm_data_zone_dissector ( proto_tree* ehs_tree, tvbuff_t* tvb, int* offset, packet_info* pinfo ) +{ + proto_item *ehs_data_zone; + proto_tree *ehs_data_zone_tree; + + int year, jday, hour, minute, second; + + /* create the data zone tree */ + ehs_data_zone = proto_tree_add_text ( ehs_tree, tvb, *offset, pinfo->iplen - IP_HEADER_LENGTH - *offset, "UDSM Data Zone" ); + ehs_data_zone_tree = proto_item_add_subtree ( ehs_data_zone, ett_ehs_data_zone ); + + proto_tree_add_item ( ehs_data_zone_tree, hf_ehs_dz_udsm_ccsds_vs_bpdu, tvb, *offset, 1, FALSE ); + /* proto_tree_add_item ( ehs_data_zone_tree, hf_ehs_dz_udsm_unused1, tvb, *offset, 1, FALSE ); */ + ++(*offset); + + /* proto_tree_add_item ( ehs_data_zone_tree, hf_ehs_dz_udsm_unused2, tvb, *offset, 1, FALSE ); */ + ++(*offset); + + /* proto_tree_add_item ( ehs_data_zone_tree, hf_ehs_dz_udsm_unused3, tvb, *offset, 2, FALSE ); */ + proto_tree_add_item ( ehs_data_zone_tree, hf_ehs_dz_udsm_gse_pkt_id, tvb, *offset, 2, FALSE ); + proto_tree_add_item ( ehs_data_zone_tree, hf_ehs_dz_udsm_payload_vs_core, tvb, *offset, 2, FALSE ); + proto_tree_add_item ( ehs_data_zone_tree, hf_ehs_dz_udsm_apid, tvb, *offset, 2, FALSE ); + *offset += 2; + + year = tvb_get_guint8 ( tvb, *offset ); + proto_tree_add_item ( ehs_data_zone_tree, hf_ehs_dz_udsm_start_time_year, tvb, *offset, 1, FALSE ); + ++(*offset); + + jday = tvb_get_ntohs ( tvb, *offset ); + proto_tree_add_item ( ehs_data_zone_tree, hf_ehs_dz_udsm_start_time_jday, tvb, *offset, 2, FALSE ); + *offset += 2; + + hour = tvb_get_guint8 ( tvb, *offset ); + proto_tree_add_item ( ehs_data_zone_tree, hf_ehs_dz_udsm_start_time_hour, tvb, *offset, 1, FALSE ); + ++(*offset); + + minute = tvb_get_guint8 ( tvb, *offset ); + proto_tree_add_item ( ehs_data_zone_tree, hf_ehs_dz_udsm_start_time_minute, tvb, *offset, 1, FALSE ); + ++(*offset); + + second = tvb_get_guint8 ( tvb, *offset ); + proto_tree_add_item ( ehs_data_zone_tree, hf_ehs_dz_udsm_start_time_second, tvb, *offset, 1, FALSE ); + ++(*offset); + + /* format a more readable time */ + proto_tree_add_text ( ehs_data_zone_tree, tvb, *offset-7, 7, + "%04d/%03d:%02d:%02d:%02d = UDSM Start Time", year + 1900, jday, hour, minute, second ); + + year = tvb_get_guint8 ( tvb, *offset ); + proto_tree_add_item ( ehs_data_zone_tree, hf_ehs_dz_udsm_stop_time_year, tvb, *offset, 1, FALSE ); + ++(*offset); + + jday = tvb_get_ntohs ( tvb, *offset ); + proto_tree_add_item ( ehs_data_zone_tree, hf_ehs_dz_udsm_stop_time_jday, tvb, *offset, 2, FALSE ); + *offset += 2; + + hour = tvb_get_guint8 ( tvb, *offset ); + proto_tree_add_item ( ehs_data_zone_tree, hf_ehs_dz_udsm_stop_time_hour, tvb, *offset, 1, FALSE ); + ++(*offset); + + minute = tvb_get_guint8 ( tvb, *offset ); + proto_tree_add_item ( ehs_data_zone_tree, hf_ehs_dz_udsm_stop_time_minute, tvb, *offset, 1, FALSE ); + ++(*offset); + + second = tvb_get_guint8 ( tvb, *offset ); + proto_tree_add_item ( ehs_data_zone_tree, hf_ehs_dz_udsm_stop_time_second, tvb, *offset, 1, FALSE ); + ++(*offset); + + /* format a more readable time */ + proto_tree_add_text ( ehs_data_zone_tree, tvb, *offset-7, 7, + "%04d/%03d:%02d:%02d:%02d = UDSM Stop Time", year + 1900, jday, hour, minute, second ); + + /* proto_tree_add_item ( ehs_data_zone_tree, hf_ehs_dz_udsm_unused4, tvb, *offset, 2, FALSE ); */ + *offset += 2; + + proto_tree_add_item ( ehs_data_zone_tree, hf_ehs_dz_udsm_num_pkts_xmtd, tvb, *offset, 2, FALSE ); + *offset += 2; + + proto_tree_add_item ( ehs_data_zone_tree, hf_ehs_dz_udsm_num_vcdu_seqerrs, tvb, *offset, 2, FALSE ); + *offset += 2; + + proto_tree_add_item ( ehs_data_zone_tree, hf_ehs_dz_udsm_num_pkt_seqerrs, tvb, *offset, 2, FALSE ); + *offset += 2; + + proto_tree_add_item ( ehs_data_zone_tree, hf_ehs_dz_udsm_num_pktlen_errors, tvb, *offset, 2, FALSE ); + *offset += 2; + + proto_tree_add_item ( ehs_data_zone_tree, hf_ehs_dz_udsm_event, tvb, *offset, 1, FALSE ); + ++(*offset); + + proto_tree_add_item ( ehs_data_zone_tree, hf_ehs_dz_udsm_num_pkts_xmtd_rollover, tvb, *offset, 1, FALSE ); + ++(*offset); + +} + + +/* data zone dissector */ +static void ehs_data_zone_dissector ( int protocol, proto_tree* ehs_tree, tvbuff_t* tvb, int* offset, packet_info* pinfo ) +{ + /* the data zone of certain protocols such as AOS/LOS and UDSM is well known. + */ + switch ( protocol ) + { + case EHS_PROTOCOL__TDM_TELEMETRY: + break; + + case EHS_PROTOCOL__NASCOM_TELEMETRY: + break; + + case EHS_PROTOCOL__PSEUDO_TELEMETRY: + break; + + case EHS_PROTOCOL__TDS_DATA: + break; + + case EHS_PROTOCOL__TEST_DATA: + break; + + case EHS_PROTOCOL__GSE_DATA: + break; + + case EHS_PROTOCOL__CUSTOM_DATA: + break; + + case EHS_PROTOCOL__HDRS_DQ: + break; + + case EHS_PROTOCOL__CSS: + break; + + case EHS_PROTOCOL__AOS_LOS: + aoslos_data_zone_dissector ( ehs_tree, tvb, offset, pinfo ); + break; + + case EHS_PROTOCOL__PDSS_PAYLOAD_CCSDS_PACKET: + break; + + case EHS_PROTOCOL__PDSS_CORE_CCSDS_PACKET: + break; + + case EHS_PROTOCOL__PDSS_PAYLOAD_BPDU: + break; + + case EHS_PROTOCOL__PDSS_UDSM: + udsm_data_zone_dissector ( ehs_tree, tvb, offset, pinfo ); + break; + + case EHS_PROTOCOL__PDSS_RPSM: + break; + + default: + break; + } +} + + +/* Code to actually dissect the packets */ +static void +dissect_ehs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + int offset = 0; + guint16 first_word; + + tvbuff_t *new_tvb; + + proto_item *ehs_packet; + proto_tree *ehs_tree; + + proto_item *ehs_primary_header; + proto_tree *ehs_primary_header_tree; + + proto_item *ehs_secondary_header; + proto_tree *ehs_secondary_header_tree; + + int protocol; + int year, jday, hour, minute, second, tenths; + + if ( check_col(pinfo->cinfo, COL_PROTOCOL) ) + col_set_str ( pinfo->cinfo, COL_PROTOCOL, "EHS" ); + if ( check_col(pinfo->cinfo, COL_INFO) ) + col_set_str ( pinfo->cinfo, COL_INFO, "EHS" ); + + if ( tree ) + { + ehs_packet = proto_tree_add_item ( tree, proto_ehs, tvb, 0, -1, FALSE ); + ehs_tree = proto_item_add_subtree ( ehs_packet, ett_ehs ); + + /* build the ehs primary header tree */ + ehs_primary_header = proto_tree_add_text ( ehs_tree, tvb, offset, EHS_PRIMARY_HEADER_SIZE, "Primary EHS Header" ); + ehs_primary_header_tree = proto_item_add_subtree ( ehs_primary_header, ett_ehs_primary_header ); + + proto_tree_add_item ( ehs_primary_header_tree, hf_ehs_ph_version, tvb, offset, 1, FALSE ); + proto_tree_add_item ( ehs_primary_header_tree, hf_ehs_ph_project, tvb, offset, 1, FALSE ); + ++offset; + + proto_tree_add_item ( ehs_primary_header_tree, hf_ehs_ph_support_mode, tvb, offset, 1, FALSE ); + proto_tree_add_item ( ehs_primary_header_tree, hf_ehs_ph_data_mode, tvb, offset, 1, FALSE ); + ++offset; + + proto_tree_add_item ( ehs_primary_header_tree, hf_ehs_ph_mission, tvb, offset, 1, FALSE ); + ++offset; + + /* save protocol for use later on */ + protocol = tvb_get_guint8 ( tvb, offset ); + proto_tree_add_item ( ehs_primary_header_tree, hf_ehs_ph_protocol, tvb, offset, 1, FALSE ); + ++offset; + + year = tvb_get_guint8 ( tvb, offset ); + proto_tree_add_item ( ehs_primary_header_tree, hf_ehs_ph_year, tvb, offset, 1, FALSE ); + ++offset; + + jday = tvb_get_ntohs ( tvb, offset ); + proto_tree_add_item ( ehs_primary_header_tree, hf_ehs_ph_jday, tvb, offset, 2, FALSE ); + offset += 2; + + hour = tvb_get_guint8 ( tvb, offset ); + proto_tree_add_item ( ehs_primary_header_tree, hf_ehs_ph_hour, tvb, offset, 1, FALSE ); + ++offset; + + minute = tvb_get_guint8 ( tvb, offset ); + proto_tree_add_item ( ehs_primary_header_tree, hf_ehs_ph_minute, tvb, offset, 1, FALSE ); + ++offset; + + second = tvb_get_guint8 ( tvb, offset ); + proto_tree_add_item ( ehs_primary_header_tree, hf_ehs_ph_second, tvb, offset, 1, FALSE ); + ++offset; + + tenths = tvb_get_guint8 ( tvb, offset ) >> 4; + proto_tree_add_item ( ehs_primary_header_tree, hf_ehs_ph_tenths, tvb, offset, 1, FALSE ); + + /* format a more readable ground receipt time string */ + proto_tree_add_text ( ehs_primary_header_tree, tvb, offset-7, 7, + "%04d/%03d:%02d:%02d:%02d.%1d = EHS Ground Receipt Time", year + 1900, jday, hour, minute, second, tenths ); + + proto_tree_add_item ( ehs_primary_header_tree, hf_ehs_ph_new_data_flag, tvb, offset, 1, FALSE ); + /* proto_tree_add_item ( ehs_primary_header_tree, hf_ehs_ph_pad1, tvb, offset, 1, FALSE ); */ + proto_tree_add_item ( ehs_primary_header_tree, hf_ehs_ph_hold_flag, tvb, offset, 1, FALSE ); + proto_tree_add_item ( ehs_primary_header_tree, hf_ehs_ph_sign_flag, tvb, offset, 1, FALSE ); + ++offset; + + /* proto_tree_add_item ( ehs_primary_header_tree, hf_ehs_ph_pad2, tvb, offset, 1, FALSE ); */ + ++offset; + /* proto_tree_add_item ( ehs_primary_header_tree, hf_ehs_ph_pad3, tvb, offset, 1, FALSE ); */ + ++offset; + /* proto_tree_add_item ( ehs_primary_header_tree, hf_ehs_ph_pad4, tvb, offset, 1, FALSE ); */ + ++offset; + + proto_tree_add_item ( ehs_primary_header_tree, hf_ehs_ph_hosc_packet_size, tvb, offset, 2, FALSE ); + offset += 2; + + /* build the ehs secondary header tree */ + ehs_secondary_header = proto_tree_add_text ( ehs_tree, tvb, offset, + ehs_secondary_header_size ( protocol, tvb, offset ), "Secondary EHS Header" ); + ehs_secondary_header_tree = proto_item_add_subtree ( ehs_secondary_header, ett_ehs_secondary_header ); + + /* since each protocol can have a different ehs secondary header structure, we will offload + * this processing to lower levels of code so we don't have to insert all of that complexity + * directly inline here, which would no doubt make this difficult to read at best. + */ + ehs_secondary_header_dissector ( protocol, ehs_secondary_header_tree, tvb, &offset ); + + /* for ccsds protocol types pass the remaining packet off to the ccsds packet dissector */ + switch ( protocol ) + { + case EHS_PROTOCOL__TDM_TELEMETRY: + case EHS_PROTOCOL__PSEUDO_TELEMETRY: + case EHS_PROTOCOL__AOS_LOS: + case EHS_PROTOCOL__PDSS_PAYLOAD_CCSDS_PACKET: + case EHS_PROTOCOL__PDSS_CORE_CCSDS_PACKET: + case EHS_PROTOCOL__PDSS_UDSM: + new_tvb = tvb_new_subset ( tvb, offset, -1, -1 ); + g_assert ( ccsds_handle != NULL ); + call_dissector ( ccsds_handle, new_tvb, pinfo, ehs_tree ); + + /* bump the offset to the data zone area */ + first_word = tvb_get_ntohs ( tvb, offset ); + + offset += CCSDS_PRIMARY_HEADER_LENGTH; + if ( first_word & HDR_SECHDR ) offset += CCSDS_SECONDARY_HEADER_LENGTH; + break; + + + default: + break; + } + + /* build the ehs data zone tree for well known protocols such as AOS/LOS and UDSM */ + ehs_data_zone_dissector ( protocol, ehs_tree, tvb, &offset, pinfo ); + } + +} + + +/* Register the protocol with Wireshark + * this format is require because a script is used to build the C function + * that calls all the protocol registration. + */ +void +proto_register_ehs(void) +{ + /* Setup list of header fields See Section 1.6.1 for details*/ + static hf_register_info hf[] = + { + /* primary ehs header */ + { &hf_ehs_ph_version, + { "Version", "ehs.version", + FT_UINT8, BASE_DEC, NULL, 0xf0, + NULL, HFILL } + }, + { &hf_ehs_ph_project, + { "Project", "ehs.project", + FT_UINT8, BASE_DEC, VALS(ehs_primary_header_project), 0x0f, + NULL, HFILL } + }, + + { &hf_ehs_ph_support_mode, + { "Support Mode", "ehs.support_mode", + FT_UINT8, BASE_DEC, VALS(ehs_primary_header_support_mode), 0xf0, + NULL, HFILL } + }, + { &hf_ehs_ph_data_mode, + { "Data Mode", "ehs.data_mode", + FT_UINT8, BASE_DEC, VALS(ehs_primary_header_data_mode), 0x0f, + NULL, HFILL } + }, + + { &hf_ehs_ph_mission, + { "Mission", "ehs.mission", + FT_UINT8, BASE_DEC, NULL, 0xff, + NULL, HFILL } + }, + + { &hf_ehs_ph_protocol, + { "Protocol", "ehs.protocol", + FT_UINT8, BASE_DEC, VALS(ehs_primary_header_protocol), 0xff, + NULL, HFILL } + }, + + { &hf_ehs_ph_year, + { "Years since 1900", "ehs.year", + FT_UINT8, BASE_DEC, NULL, 0xff, + NULL, HFILL } + }, + + { &hf_ehs_ph_jday, + { "Julian Day of Year", "ehs.jday", + FT_UINT16, BASE_DEC, NULL, 0xffff, + NULL, HFILL } + }, + + { &hf_ehs_ph_hour, + { "Hour", "ehs.hour", + FT_UINT8, BASE_DEC, NULL, 0xff, + NULL, HFILL } + }, + + { &hf_ehs_ph_minute, + { "Minute", "ehs.minute", + FT_UINT8, BASE_DEC, NULL, 0xff, + NULL, HFILL } + }, + + { &hf_ehs_ph_second, + { "Second", "ehs.second", + FT_UINT8, BASE_DEC, NULL, 0xff, + NULL, HFILL } + }, + + { &hf_ehs_ph_tenths, + { "Tenths", "ehs.tenths", + FT_UINT8, BASE_DEC, NULL, 0xf0, + NULL, HFILL } + }, + { &hf_ehs_ph_new_data_flag, + { "New Data Flag", "ehs.new_data_flag", + FT_BOOLEAN, 8, NULL, 0x08, + NULL, HFILL } + }, + { &hf_ehs_ph_pad1, + { "Pad1", "ehs.pad1", + FT_UINT8, BASE_DEC, NULL, 0x04, + NULL, HFILL } + }, + { &hf_ehs_ph_hold_flag, + { "Hold Flag", "ehs.hold_flag", + FT_BOOLEAN, 8, NULL, 0x02, + NULL, HFILL } + }, + { &hf_ehs_ph_sign_flag, + { "Sign Flag (1->CDT)", "ehs.sign_flag", + FT_UINT8, BASE_DEC, NULL, 0x01, + NULL, HFILL } + }, + + { &hf_ehs_ph_pad2, + { "Pad2", "ehs.pad2", + FT_UINT8, BASE_DEC, NULL, 0xff, + NULL, HFILL } + }, + + { &hf_ehs_ph_pad3, + { "Pad3", "ehs.pad3", + FT_UINT8, BASE_DEC, NULL, 0xff, + NULL, HFILL } + }, + + { &hf_ehs_ph_pad4, + { "Pad4", "ehs.pad4", + FT_UINT8, BASE_DEC, NULL, 0xff, + NULL, HFILL } + }, + + { &hf_ehs_ph_hosc_packet_size, + { "HOSC Packet Size", "ehs.hosc_packet_size", + FT_UINT16, BASE_DEC, NULL, 0xffff, + NULL, HFILL } + }, + + + /* secondary ehs header */ + { &hf_ehs_sh_version, + { "Version", "ehs2.version", + FT_UINT8, BASE_DEC, NULL, 0xc0, + NULL, HFILL } + }, + { &hf_ehs_sh_data_status_bit_5, + { "Data Status Bit 5", "ehs2.data_status_bit_5", + FT_UINT8, BASE_DEC, NULL, 0x20, + NULL, HFILL } + }, + { &hf_ehs_sh_data_status_bit_4, + { "Data Status Bit 4", "ehs2.data_status_bit_4", + FT_UINT8, BASE_DEC, NULL, 0x10, + NULL, HFILL } + }, + { &hf_ehs_sh_data_status_bit_3, + { "Data Status Bit 3", "ehs2.data_status_bit_3", + FT_UINT8, BASE_DEC, NULL, 0x08, + NULL, HFILL } + }, + { &hf_ehs_sh_data_status_bit_2, + { "Data Status Bit 2", "ehs2.data_status_bit_2", + FT_UINT8, BASE_DEC, NULL, 0x04, + NULL, HFILL } + }, + { &hf_ehs_sh_data_status_bit_1, + { "Data Status Bit 1", "ehs2.data_status_bit_1", + FT_UINT8, BASE_DEC, NULL, 0x02, + NULL, HFILL } + }, + { &hf_ehs_sh_data_status_bit_0, + { "Data Status Bit 0", "ehs2.data_status_bit_0", + FT_UINT8, BASE_DEC, NULL, 0x01, + NULL, HFILL } + }, + + + /* other common remappings of the data status bits specific to certain secondary ehs header values */ + { &hf_ehs_sh_parent_stream_error, + { "Parent Stream Error", "ehs2.parent_stream_error", + FT_BOOLEAN, 8, NULL, 0x08, + NULL, HFILL } + }, + { &hf_ehs_sh_vcdu_sequence_error, + { "VCDU Sequence Error", "ehs2.vcdu_sequence_error", + FT_BOOLEAN, 8, NULL, 0x04, + NULL, HFILL } + }, + { &hf_ehs_sh_packet_sequence_error, + { "Packet Sequence Error", "ehs2.packet_sequence_error", + FT_UINT8, BASE_DEC, NULL, 0x02, + NULL, HFILL } + }, + + + /* common ehs secondary header values */ + { &hf_ehs_sh_vcdu_sequence_number, + { "VCDU Sequence Number", "ehs2.vcdu_seqno", + FT_UINT24, BASE_DEC, NULL, 0xffffff, + NULL, HFILL } + }, + + { &hf_ehs_sh_data_stream_id, + { "Data Stream ID", "ehs2.data_stream_id", + FT_UINT8, BASE_DEC, VALS(ehs_secondary_header_data_stream_id), 0x80, + NULL, HFILL } + }, + { &hf_ehs_sh_pdss_reserved_1, + { "Pdss Reserved 1", "ehs2.pdss_reserved_1", + FT_UINT8, BASE_DEC, NULL, 0x7f, + NULL, HFILL } + }, + + { &hf_ehs_sh_pdss_reserved_2, + { "Pdss Reserved 2", "ehs2.pdss_reserved_2", + FT_UINT8, BASE_DEC, NULL, 0xff, + NULL, HFILL } + }, + + { &hf_ehs_sh_pdss_reserved_3, + { "Pdss Reserved 3", "ehs2.pdss_reserved_3", + FT_UINT16, BASE_DEC, NULL, 0xe000, + NULL, HFILL } + }, + { &hf_ehs_sh_gse_pkt_id, + { "GSE Packet ID (1=GSE)", "ehs2.gse_pkt_id", + FT_UINT16, BASE_DEC, NULL, 0x1000, + NULL, HFILL } + }, + { &hf_ehs_sh_payload_vs_core_id, + { "Payload vs Core ID", "ehs2.payload_vs_core_id", + FT_UINT16, BASE_DEC, VALS(ehs_secondary_header_payload_vs_core_id), 0x0800, + NULL, HFILL } + }, + { &hf_ehs_sh_apid, + { "APID", "ehs2.apid", + FT_UINT16, BASE_DEC, NULL, 0x07ff, + NULL, HFILL } + }, + + { &hf_ehs_sh_virtual_channel, + { "Virtual Channel", "ehs2.vcid", + FT_UINT16, BASE_DEC, NULL, 0xffff, + NULL, HFILL } + }, + + { &hf_ehs_sh_pdss_reserved_sync, + { "Pdss Reserved Sync", "ehs2.sync", + FT_UINT16, BASE_HEX, NULL, 0xffff, + NULL, HFILL } + }, + + + /* tdm ehs secondary header values */ + { &hf_ehs_sh_tdm_secondary_header_length, + { "Secondary Header Length", "ehs2.tdm_secondary_header_length", + FT_UINT16, BASE_DEC, NULL, 0xffff, + NULL, HFILL } + }, + + { &hf_ehs_sh_tdm_extra_data_packet, + { "Extra Data Packet", "ehs2.tdm_extra_data_packet", + FT_BOOLEAN, 8, NULL, 0x80, + NULL, HFILL } + }, + { &hf_ehs_sh_tdm_backup_stream_id_number, + { "Backup Stream ID Number", "ehs2.tdm_backup_stream_id_number", + FT_UINT8, BASE_DEC, VALS(ehs_secondary_header_tdm_backup_stream_id), 0x60, + NULL, HFILL } + }, + { &hf_ehs_sh_tdm_end_of_data_flag, + { "End of Data Flag", "ehs2tdm_end_of_data_flag.tdm_end_of_data_flag", + FT_UINT8, BASE_DEC, VALS(ehs_secondary_header_tdm_end_of_data_flag), 0x18, + NULL, HFILL } + }, + { &hf_ehs_sh_tdm_parent_frame_error, + { "Parent Frame Error", "ehs2.tdm_parent_frame_error", + FT_BOOLEAN, 8, NULL, 0x04, + NULL, HFILL } + }, + { &hf_ehs_sh_tdm_checksum_error, + { "Checksum Error", "ehs2.tdm_checksum_error", + FT_BOOLEAN, 8, NULL, 0x02, + NULL, HFILL } + }, + { &hf_ehs_sh_tdm_fixed_value_error, + { "Fixed Value Error", "ehs2.tdm_fixed_value_error", + FT_BOOLEAN, 8, NULL, 0x01, + NULL, HFILL } + }, + + { &hf_ehs_sh_tdm_minor_frame_counter_error, + { "Minor Frame Counter Error", "ehs2.tdm_minor_frame_counter_error", + FT_BOOLEAN, 8, NULL, 0x80, + NULL, HFILL } + }, + { &hf_ehs_sh_tdm_format_id_error, + { "Format ID Error", "ehs2.tdm_format_id_error", + FT_BOOLEAN, 8, NULL, 0x40, + NULL, HFILL } + }, + { &hf_ehs_sh_tdm_bit_slip_error, + { "Bit Slip Error", "ehs2.tdm_bit_slip_error", + FT_BOOLEAN, 8, NULL, 0x20, + NULL, HFILL } + }, + { &hf_ehs_sh_tdm_sync_error, + { "Sync Error", "ehs2.tdm_sync_error", + FT_BOOLEAN, 8, NULL, 0x10, + NULL, HFILL } + }, + { &hf_ehs_sh_tdm_aoslos_flag, + { "AOS/LOS Flag", "ehs2.tdm_aoslos_flag", + FT_BOOLEAN, 8, VALS(ehs_secondary_header_tdm_aoslos_flag), 0x08, + NULL, HFILL } + }, + { &hf_ehs_sh_tdm_override_errors_flag, + { "Override Errors", "ehs2.tdm_override_errors_flag", + FT_BOOLEAN, 8, NULL, 0x04, + NULL, HFILL } + }, + { &hf_ehs_sh_tdm_data_status, + { "Data Status", "ehs2.tdm_data_status", + FT_UINT8, BASE_DEC, VALS(ehs_secondary_header_tdm_data_status), 0x03, + NULL, HFILL } + }, + + { &hf_ehs_sh_tdm_idq, + { "IDQ", "ehs2.tdm_idq", + FT_UINT16, BASE_DEC, NULL, 0xffff, + NULL, HFILL } + }, + + { &hf_ehs_sh_tdm_cdq, + { "CDQ", "ehs2.tdm_cdq", + FT_UINT16, BASE_DEC, NULL, 0xffff, + NULL, HFILL } + }, + + { &hf_ehs_sh_tdm_adq, + { "ADQ", "ehs2.tdm_adq", + FT_UINT16, BASE_DEC, NULL, 0xffff, + NULL, HFILL } + }, + + { &hf_ehs_sh_tdm_data_dq, + { "Data DQ", "ehs2.tdm_data_dq", + FT_UINT16, BASE_DEC, NULL, 0xffff, + NULL, HFILL } + }, + + { &hf_ehs_sh_tdm_unused, + { "Unused", "ehs2.tdm_unused", + FT_UINT16, BASE_DEC, NULL, 0xffff, + NULL, HFILL } + }, + + { &hf_ehs_sh_tdm_format_id, + { "Format ID", "ehs2.tdm_format_id", + FT_UINT16, BASE_HEX, NULL, 0xffff, + NULL, HFILL } + }, + + { &hf_ehs_sh_tdm_major_frame_packet_index, + { "Major Frame Packet Index", "ehs2.tdm_major_frame_packet_index", + FT_UINT8, BASE_DEC, NULL, 0xff, + NULL, HFILL } + }, + + { &hf_ehs_sh_tdm_numpkts_per_major_frame, + { "Num Packets per Major Frame", "ehs2.tdm_numpkts_per_major_frame", + FT_UINT8, BASE_DEC, NULL, 0xff, + NULL, HFILL } + }, + + { &hf_ehs_sh_tdm_num_minor_frames_per_packet, + { "Num Minor Frames per Packet", "ehs2.tdm_num_minor_frame_per_packet", + FT_UINT8, BASE_DEC, NULL, 0xff, + NULL, HFILL } + }, + + { &hf_ehs_sh_tdm_cntmet_present, + { "CNT or MET Present", "ehs2.tdm_cntmet_present", + FT_BOOLEAN, 8, NULL, 0x80, + NULL, HFILL } + }, + { &hf_ehs_sh_tdm_obt_present, + { "OBT Present", "ehs2.tdm_obt_present", + FT_BOOLEAN, 8, NULL, 0x40, + NULL, HFILL } + }, + { &hf_ehs_sh_tdm_major_frame_status_present, + { "Major Frame Status Present", "ehs2.tdm_major_frame_status_present", + FT_BOOLEAN, 8, NULL, 0x20, + NULL, HFILL } + }, + { &hf_ehs_sh_tdm_reserved, + { "Reserved", "ehs2.tdm_reserved", + FT_UINT8, BASE_DEC, NULL, 0x1f, + NULL, HFILL } + }, + + { &hf_ehs_sh_tdm_cnt_year, + { "CNT Years since 1900", "ehs2.tdm_cnt_year", + FT_UINT8, BASE_DEC, NULL, 0xff, + NULL, HFILL } + }, + { &hf_ehs_sh_tdm_cnt_jday, + { "CNT Julian Day of Year", "ehs2.tdm_cnt_jday", + FT_UINT16, BASE_DEC, NULL, 0xffff, + NULL, HFILL } + }, + { &hf_ehs_sh_tdm_cnt_hour, + { "CNT Hour", "ehs2.tdm_cnt_hour", + FT_UINT8, BASE_DEC, NULL, 0xff, + NULL, HFILL } + }, + { &hf_ehs_sh_tdm_cnt_minute, + { "CNT Minute", "ehs2.tdm_cnt_minute", + FT_UINT8, BASE_DEC, NULL, 0xff, + NULL, HFILL } + }, + { &hf_ehs_sh_tdm_cnt_second, + { "CNT Second", "ehs2.tdm_cnt_second", + FT_UINT8, BASE_DEC, NULL, 0xff, + NULL, HFILL } + }, + { &hf_ehs_sh_tdm_cnt_tenths, + { "CNT Tenths", "ehs2.tdm_cnt_tenths", + FT_UINT8, BASE_DEC, NULL, 0xf0, + NULL, HFILL } + }, + + { &hf_ehs_sh_tdm_obt_year, + { "OBT Years since 1900", "ehs2.tdm_cnt_year", + FT_UINT8, BASE_DEC, NULL, 0xff, + NULL, HFILL } + }, + { &hf_ehs_sh_tdm_obt_jday, + { "OBT Julian Day of Year", "ehs2.tdm_cnt_jday", + FT_UINT16, BASE_DEC, NULL, 0xffff, + NULL, HFILL } + }, + { &hf_ehs_sh_tdm_obt_hour, + { "OBT Hour", "ehs2.tdm_cnt_hour", + FT_UINT8, BASE_DEC, NULL, 0xff, + NULL, HFILL } + }, + { &hf_ehs_sh_tdm_obt_minute, + { "OBT Minute", "ehs2.tdm_cnt_minute", + FT_UINT8, BASE_DEC, NULL, 0xff, + NULL, HFILL } + }, + { &hf_ehs_sh_tdm_obt_second, + { "OBT Second", "ehs2.tdm_cnt_second", + FT_UINT8, BASE_DEC, NULL, 0xff, + NULL, HFILL } + }, + { &hf_ehs_sh_tdm_obt_tenths, + { "OBT Tenths", "ehs2.tdm_cnt_tenths", + FT_UINT8, BASE_DEC, NULL, 0xf0, + NULL, HFILL } + }, + + { &hf_ehs_sh_tdm_obt_delta_time_flag, + { "OBT is Delta Time Instead of GMT", "ehs2.tdm_obt_delta_time_flag", + FT_BOOLEAN, 16, NULL, 0x8000, + NULL, HFILL } + }, + { &hf_ehs_sh_tdm_obt_computed_flag, + { "OBT Computed", "ehs2.tdm_obt_computed_flag", + FT_BOOLEAN, 16, NULL, 0x4000, + NULL, HFILL } + }, + { &hf_ehs_sh_tdm_obt_not_retrieved_flag, + { "OBT Not Retrieved", "ehs2.tdm_obt_not_retrieved_flag", + FT_BOOLEAN, 16, NULL, 0x2000, + NULL, HFILL } + }, + { &hf_ehs_sh_tdm_obt_reserved, + { "OBT Reserved", "ehs2.tdm_obt_reserved", + FT_BOOLEAN, 16, NULL, 0x1800, + NULL, HFILL } + }, + { &hf_ehs_sh_tdm_obt_source_apid, + { "OBT Source APID", "ehs2.tdm_obt_source_apid", + FT_UINT16, BASE_DEC, NULL, 0x07ff, + NULL, HFILL } + }, + + { &hf_ehs_sh_tdm_num_major_frame_status_words, + { "Number of Major Frame Status Words", "ehs2.tdm_num_major_frame_status_words", + FT_UINT8, BASE_DEC, NULL, 0x0ff, + NULL, HFILL } + }, + + { &hf_ehs_sh_tdm_mjfs_reserved, + { "Reserved", "ehs2.tdm_mjfs_reserved", + FT_UINT8, BASE_DEC, NULL, 0xf8, + NULL, HFILL } + }, + { &hf_ehs_sh_tdm_mjfs_parent_frame_error, + { "Parent Frame Error", "ehs2.tdm_mjfs_parent_frame_error", + FT_BOOLEAN, 8, NULL, 0x04, + NULL, HFILL } + }, + { &hf_ehs_sh_tdm_mjfs_checksum_error, + { "Checksum Error", "ehs2.tdm_mjfs_checksum_error", + FT_BOOLEAN, 8, NULL, 0x02, + NULL, HFILL } + }, + { &hf_ehs_sh_tdm_mjfs_fixed_value_error, + { "Fixed Value Error", "ehs2.tdm_mjfs_fixed_value_error", + FT_BOOLEAN, 8, NULL, 0x01, + NULL, HFILL } + }, + + { &hf_ehs_sh_tdm_mnfs_parent_frame_error, + { "Parent Frame Error", "ehs2.tdm_mnfs_parent_frame_error", + FT_BOOLEAN, 8, NULL, 0x80, + NULL, HFILL } + }, + { &hf_ehs_sh_tdm_mnfs_data_not_available, + { "Data Not Available", "ehs2.tdm_mnfs_data_not_available", + FT_BOOLEAN, 8, NULL, 0x40, + NULL, HFILL } + }, + { &hf_ehs_sh_tdm_mnfs_checksum_error, + { "Checksum Error", "ehs2.tdm_mnfs_checksum_error", + FT_BOOLEAN, 8, NULL, 0x20, + NULL, HFILL } + }, + { &hf_ehs_sh_tdm_mnfs_fixed_value_error, + { "Fixed Value Error", "ehs2.tdm_mnfs_fixed_value_error", + FT_BOOLEAN, 8, NULL, 0x10, + NULL, HFILL } + }, + { &hf_ehs_sh_tdm_mnfs_counter_error, + { "Counter Error", "ehs2.tdm_mnfs_counter_error", + FT_BOOLEAN, 8, NULL, 0x08, + NULL, HFILL } + }, + { &hf_ehs_sh_tdm_mnfs_format_id_error, + { "Format ID Error", "ehs2.tdm_mnfs_format_id_error", + FT_BOOLEAN, 8, NULL, 0x04, + NULL, HFILL } + }, + { &hf_ehs_sh_tdm_mnfs_bit_slip_error, + { "Bit Slip Error", "ehs2.tdm_mnfs_bit_slip_error", + FT_BOOLEAN, 8, NULL, 0x02, + NULL, HFILL } + }, + { &hf_ehs_sh_tdm_mnfs_sync_error, + { "Sync Error", "ehs2.tdm_mnfs_sync_error", + FT_BOOLEAN, 8, NULL, 0x01, + NULL, HFILL } + }, + + + /* pseudo secondary header */ + { &hf_ehs_sh_pseudo_unused, + { "Unused", "ehs2.pseudo_unused", + FT_UINT16, BASE_DEC, NULL, 0xffff, + NULL, HFILL } + }, + { &hf_ehs_sh_pseudo_workstation_id, + { "Workstation ID", "ehs2.pseudo_workstation_id", + FT_UINT16, BASE_DEC, NULL, 0xffff, + NULL, HFILL } + }, + { &hf_ehs_sh_pseudo_user_id, + { "User ID", "ehs2.pseudo_user_id", + FT_UINT16, BASE_DEC, NULL, 0xffff, + NULL, HFILL } + }, + { &hf_ehs_sh_pseudo_comp_id, + { "Comp ID", "ehs2.pseudo_comp_id", + FT_UINT16, BASE_DEC, NULL, 0xffff, + NULL, HFILL } + }, + + + /* aos/los protocol data zone */ + { &hf_ehs_dz_aoslos_indicator, + { "AOS/LOS Indicator", "dz.aoslos_indicator", + FT_UINT8, BASE_DEC, VALS(ehs_data_zone_aoslos_indicator), 0x03, + NULL, HFILL } + }, + + + /* udsm protocol data zone */ + { &hf_ehs_dz_udsm_ccsds_vs_bpdu, + { "CCSDS vs BPDU", "dz.udsm_ccsds_vs_bpdu", + FT_UINT8, BASE_DEC, VALS(ehs_data_zone_udsm_ccsds_vs_bpdu), 0x80, + NULL, HFILL } + }, + { &hf_ehs_dz_udsm_unused1, + { "Unused 1", "dz.udsm_unused1", + FT_UINT8, BASE_DEC, NULL, 0x7f, + NULL, HFILL } + }, + + { &hf_ehs_dz_udsm_unused2, + { "Unused 2", "dz.udsm_unused2", + FT_UINT8, BASE_DEC, NULL, 0xff, + NULL, HFILL } + }, + + { &hf_ehs_dz_udsm_unused3, + { "Unused 3", "dz.udsm_unused3", + FT_UINT16, BASE_DEC, NULL, 0xe000, + NULL, HFILL } + }, + { &hf_ehs_dz_udsm_gse_pkt_id, + { "GSE Pkt ID", "dz.udsm_gse_pkt_id", + FT_BOOLEAN, 16, NULL, 0x1000, + NULL, HFILL } + }, + { &hf_ehs_dz_udsm_payload_vs_core, + { "Payload vs Core", "dz.udsm_payload_vs_core", + FT_UINT16, BASE_DEC, VALS(ehs_data_zone_udsm_payload_vs_core), 0x0800, + NULL, HFILL } + }, + { &hf_ehs_dz_udsm_apid, + { "APID", "dz.udsm_apid", + FT_UINT16, BASE_DEC, NULL, 0x07ff, + NULL, HFILL } + }, + + { &hf_ehs_dz_udsm_start_time_year, + { "Start Time Years since 1900", "dz.udsm_start_time_year", + FT_UINT8, BASE_DEC, NULL, 0xff, + NULL, HFILL } + }, + { &hf_ehs_dz_udsm_start_time_jday, + { "Start Time Julian Day", "dz.udsm_start_time_jday", + FT_UINT16, BASE_DEC, NULL, 0xffff, + NULL, HFILL } + }, + { &hf_ehs_dz_udsm_start_time_hour, + { "Start Time Hour", "dz.udsm_start_time_hour", + FT_UINT8, BASE_DEC, NULL, 0xff, + NULL, HFILL } + }, + { &hf_ehs_dz_udsm_start_time_minute, + { "Start Time Minute", "dz.udsm_start_time_minute", + FT_UINT8, BASE_DEC, NULL, 0xff, + NULL, HFILL } + }, + { &hf_ehs_dz_udsm_start_time_second, + { "Start Time Second", "dz.udsm_start_time_second", + FT_UINT8, BASE_DEC, NULL, 0xff, + NULL, HFILL } + }, + + { &hf_ehs_dz_udsm_stop_time_year, + { "Stop Time Years since 1900", "dz.udsm_stop_time_year", + FT_UINT8, BASE_DEC, NULL, 0xff, + NULL, HFILL } + }, + { &hf_ehs_dz_udsm_stop_time_jday, + { "Stop Time Julian Day", "dz.udsm_stop_time_jday", + FT_UINT16, BASE_DEC, NULL, 0xffff, + NULL, HFILL } + }, + { &hf_ehs_dz_udsm_stop_time_hour, + { "Stop Time Hour", "dz.udsm_stop_time_hour", + FT_UINT8, BASE_DEC, NULL, 0xff, + NULL, HFILL } + }, + { &hf_ehs_dz_udsm_stop_time_minute, + { "Stop Time Minute", "dz.udsm_stop_time_minute", + FT_UINT8, BASE_DEC, NULL, 0xff, + NULL, HFILL } + }, + { &hf_ehs_dz_udsm_stop_time_second, + { "Stop Time Second", "dz.udsm_stop_time_second", + FT_UINT8, BASE_DEC, NULL, 0xff, + NULL, HFILL } + }, + + { &hf_ehs_dz_udsm_unused4, + { "Unused 4", "dz.udsm_unused4", + FT_UINT16, BASE_DEC, NULL, 0xffff, + NULL, HFILL } + }, + + { &hf_ehs_dz_udsm_num_pkts_xmtd, + { "Num Pkts Transmitted", "dz.udsm_num_pkts_xmtd", + FT_UINT16, BASE_DEC, NULL, 0xffff, + NULL, HFILL } + }, + + { &hf_ehs_dz_udsm_num_vcdu_seqerrs, + { "Num VCDU Sequence Errors", "dz.udsm_num_vcdu_seqerrs", + FT_UINT16, BASE_DEC, NULL, 0xffff, + NULL, HFILL } + }, + + { &hf_ehs_dz_udsm_num_pkt_seqerrs, + { "Num Packet Sequence Errors", "dz.udsm_num_pkt_seqerrs", + FT_UINT16, BASE_DEC, NULL, 0xffff, + NULL, HFILL } + }, + + { &hf_ehs_dz_udsm_num_pktlen_errors, + { "Num Pkt Length Errors", "dz.udsm_num_pktlen_errors", + FT_UINT16, BASE_DEC, NULL, 0xffff, + NULL, HFILL } + }, + + { &hf_ehs_dz_udsm_event, + { "UDSM Event Code", "dz.udsm_event", + FT_UINT8, BASE_DEC, VALS(ehs_data_zone_udsm_event), 0xff, + NULL, HFILL } + }, + + { &hf_ehs_dz_udsm_num_pkts_xmtd_rollover, + { "Num Pkts Transmitted Rollover Counter", "dz.udsm_num_pkts_xmtd_rollover", + FT_UINT8, BASE_DEC, NULL, 0xff, + NULL, HFILL } + }, + + }; + + /* Setup protocol subtree array */ + static gint *ett[] = { + &ett_ehs, + &ett_ehs_primary_header, + &ett_ehs_secondary_header, + &ett_ehs_data_zone + }; + + /* Register the protocol name and description */ + proto_ehs = proto_register_protocol("EHS", "EHS", "ehs"); + + /* Required function calls to register the header fields and subtrees used */ + proto_register_field_array(proto_ehs, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + +} + + +/* If this dissector uses sub-dissector registration add a registration routine. + * This format is required because a script is used to find these routines and + * create the code that calls these routines. + */ +void +proto_reg_handoff_ehs(void) +{ + register_dissector ( "ehs", dissect_ehs, proto_ehs ); + dissector_add ( "udp.port", 0, find_dissector("ehs") ); + ccsds_handle = find_dissector ( "ccsds" ); +} + diff --git a/epan/dissectors/packet-vcdu.c b/epan/dissectors/packet-vcdu.c new file mode 100644 index 0000000000..bb6fba853f --- /dev/null +++ b/epan/dissectors/packet-vcdu.c @@ -0,0 +1,648 @@ +/* packet-vcdu.c + * Routines for VCDU dissection + * Copyright 2000, Scott Hovis scott.hovis@ums.msfc.nasa.gov + * Enhanced 2008, Matt Dunkle Matthew.L.Dunkle@nasa.gov + * + * $Id$ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.com> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <glib.h> +#include <epan/packet.h> +#include <epan/filesystem.h> + + +/* Initialize the protocol and registered fields */ +static int proto_vcdu = -1; + +static int hf_smex_gsc = -1; +static int hf_smex_unused = -1; +static int hf_smex_version = -1; +static int hf_smex_framelen = -1; +static int hf_smex_rs_error = -1; +static int hf_smex_rs_enable = -1; +static int hf_smex_crc_enable = -1; +static int hf_smex_crc_error = -1; +static int hf_smex_mcs_enable = -1; +static int hf_smex_mcs_num_error = -1; +static int hf_smex_data_inv = -1; +static int hf_smex_frame_sync = -1; +static int hf_smex_data_dir = -1; +static int hf_smex_data_class = -1; +static int hf_smex_pb5 = -1; +static int hf_smex_jday = -1; +static int hf_smex_seconds = -1; +static int hf_smex_msec = -1; +static int hf_smex_spare = -1; + +static int hf_vcdu_version = -1; +static int hf_vcdu_sp_id = -1; +static int hf_vcdu_vc_id = -1; +static int hf_vcdu_seq = -1; +static int hf_vcdu_replay = -1; + +/* although technically not part of the vcdu header, the + * first header pointer (for ccsds), and the last bit + * pointer (for bitstream), are more easily processed by + * simply adding them to the tail end of the vcdu header + * branch rather than creating a distinct branch for them + */ +static int hf_vcdu_fhp = -1; +static int hf_vcdu_lbp = -1; + +static dissector_handle_t ccsds_handle = (dissector_handle_t)-1; + +/* Initialize the subtree pointers */ +static gint ett_vcdu = -1; +static gint ett_smex = -1; +static gint ett_vcduh = -1; + +/* + * Bits in the first 16-bit header word + */ +#define SMEX_VERSION 0xc000 +#define SMEX_FRAMELEN 0x3fff + +/* some basic sizing parameters */ +#define IP_HEADER_LENGTH 48 +#define SMEX_HEADER_LENGTH 20 +#define VCDU_HEADER_LENGTH 6 +#define CCSDS_PRIMARY_HEADER_LENGTH 6 +#define CCSDS_SECONDARY_HEADER_LENGTH 10 + +#define PB5_JULIAN_DAY_MASK 0x7ffe +#define PB5_SECONDS_MASK 0x01ffff +#define PB5_MILLISECONDS_MASK 0xffc0 + +#define LBP_ALL_DATA 0x3fff +#define LBP_ALL_DATA_ANOMALY 0x7ff +#define LBP_ALL_FILL 0x3ffe + +#define FHP_ALL_FILL 0x7fe +#define FHP_CONTINUATION 0x7ff + +#define LBP_MASK 0x3fff +#define FHP_MASK 0x7ff + +/* leap year macro */ +#ifndef Leap +# define Leap(yr) ( ( 0 == (yr)%4 && 0 != (yr)%100 ) || ( 0 == (yr)%400 ) ) +#endif + + +static const value_string smex_data_inversion_type[] = { + { 0, "Data True (not inverted)" }, + { 1, "Data Inverted (not corrected)" }, + { 2, "Data Inversion State UNDEFINED" }, + { 3, "Data Inverted (and corrected)" }, + { 0, NULL } +}; + +static const value_string smex_frame_sync_mode[] = { + { 0, "Search" }, + { 1, "Check" }, + { 2, "Lock" }, + { 3, "Flywheel" }, + { 0, NULL } +}; + +static const value_string smex_data_direction[] = { + { 0, "Forward" }, + { 1, "Reverse" }, + { 0, NULL } +}; + +static const value_string smex_data_class[] = { + { 0, "Data Class UNDEFINED" }, + { 1, "CCSDS Frame" }, + { 2, "CCSDS Packet" }, + { 3, "TDM Frame" }, + { 4, "Stopped TDM Frame" }, + { 0, NULL } +}; + + + + +/* prototype of utc to julian time conversion function - see packet-ccsds.c for the full source code */ +extern void utc_to_julian ( int utc, int* year, int* julianday, int* hour, int* minute, int* second ); + + +/* convert smex PB5 header time to a human readable string - NOT THREAD SAFE + * + * note: this is not true PB5 time either, but a tsi specific version, although it is similar + */ +static const char* smex_time_to_string ( int pb5_days_since_midnight_9_10_oct_1995, int pb5_seconds, int pb5_milliseconds ) +{ + static const char* fmt = "%04d/%03d:%02d:%02d:%02d.%03d"; + static char juliantime[40]; + static int utcdiff = 0; + + static int Days[2][13] = + { + { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } + }; + + int utc, yr, year, julianday, hour, minute, second; + int ix, days, month; + + /* compute the static constant difference in seconds + * between midnight 9-10 October 1995 (PB5 time) and + * seconds since 1/1/1970 (UTC time) just this once + */ + if ( 0 == utcdiff ) + { + for ( yr=1970; yr < 1995; ++yr ) + { + utcdiff += ( Leap(yr) ? 366 : 365 ) * 24 * 60 * 60; + } + + days = 0; + ix = ( Leap(1995) ? 1 : 0 ); + + for ( month=1; month < 10; ++month ) + { + days += Days[ix][month]; + } + + days += 9; /* this gets us up to midnight october 9-10 */ + + utcdiff += days * 24 * 60 * 60; /* add days in 1995 prior to October 10 */ + } + + utc = ( pb5_days_since_midnight_9_10_oct_1995 * 86400 ) + pb5_seconds + utcdiff; + utc_to_julian ( utc, &year, &julianday, &hour, &minute, &second ); + + g_snprintf ( juliantime, sizeof(juliantime), fmt, year, julianday, hour, minute, second, pb5_milliseconds ); + + return juliantime; + +} + + +/* Code to actually dissect the packets */ +static void +dissect_vcdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + static int bitstream_channels_file_read = 0; + + /* default bitstream channel assignments: + * the audio channels 4-6 are designated as bitstream channels + * the standard bitstream channels are 12 through 19 + * the video channels 28-30 are designated as bitstream channels + * the fill channel 63 is designated as bitstream + */ + static int bitstream_channels[] = + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* channels 0-9 */ + 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /* channels 10-19 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* channels 20-29 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* channels 30-39 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* channels 40-49 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* channels 50-59 */ + 0, 0, 0, 1 /* channels 60-63 */ + }; + + int packet_boundary = 0; + int offset = 0; + int new_offset=0; + int ccsds_tree_added = 0; + + int apid = 0; + int ccsds_len = 0; + + proto_item *smex_header = NULL; + proto_tree *smex_tree = NULL; + + proto_item *vcdu_header = NULL; + proto_tree *vcdu_tree = NULL; + + guint16 first_word = 0; + guint32 long_word = 0; + guint16 new_ptr = 0; + + tvbuff_t *new_tvb = NULL; + + int channel = 0, vcid = 0; + char *filename = NULL; + char *endptr = NULL, *cptr = NULL; + FILE* fp = NULL; + char readbuf[1024]; + + int pb5_days = 0, pb5_seconds = 0, pb5_milliseconds = 0; + const char* time_string = NULL; + + + /* if the bitstream channels file has not been read attempt to do so now. + * this file potentially contains a modified list of the channels that + * should be processed as bitstream instead of ccsds. + */ + if ( ! bitstream_channels_file_read ) + { + bitstream_channels_file_read = 1; + filename = get_persconffile_path ( ".bitstream_channels", FALSE, FALSE ); + fp = fopen ( filename, "r" ); + + if ( NULL != fp ) + { + if ( fgets ( readbuf, sizeof(readbuf), fp ) == readbuf ) + { + memset ( bitstream_channels, 0, sizeof(bitstream_channels) ); + cptr = readbuf; + + while ( TRUE ) + { + channel = strtoul ( cptr, &endptr, 0 ); + if ( cptr == endptr ) break; + + if ( channel >= 0 && channel < 64 ) + { + bitstream_channels[channel] = 1; + } + + cptr = endptr; + } + } + + fclose(fp); + g_free(filename); + } + } + + if (check_col(pinfo->cinfo, COL_PROTOCOL)) + col_set_str(pinfo->cinfo, COL_PROTOCOL, "VCDU"); + if (check_col(pinfo->cinfo, COL_INFO)) + col_set_str(pinfo->cinfo, COL_INFO, "Virtual Channel Data Unit"); + + if (tree) { + /* build the smex header tree */ + smex_header=proto_tree_add_text(tree, tvb, offset, SMEX_HEADER_LENGTH, "SMEX Header"); + smex_tree=proto_item_add_subtree(smex_header, ett_smex); + + proto_tree_add_item(smex_tree, hf_smex_gsc, tvb, offset, 8, FALSE); + offset += 8; + /* proto_tree_add_uint(smex_tree, hf_smex_unused, tvb, offset, 2, FALSE); */ + offset += 2; + + first_word=tvb_get_ntohs(tvb, offset); + proto_tree_add_uint(smex_tree, hf_smex_version, tvb, offset, 2, first_word); + proto_tree_add_uint(smex_tree, hf_smex_framelen, tvb, offset, 2, first_word); + offset += 2; + + proto_tree_add_item(smex_tree, hf_smex_rs_enable, tvb, offset, 1, FALSE); + proto_tree_add_item(smex_tree, hf_smex_rs_error, tvb, offset, 1, FALSE); + proto_tree_add_item(smex_tree, hf_smex_crc_enable, tvb, offset, 1, FALSE); + proto_tree_add_item(smex_tree, hf_smex_crc_error, tvb, offset, 1, FALSE); + proto_tree_add_item(smex_tree, hf_smex_mcs_enable, tvb, offset, 1, FALSE); + proto_tree_add_item(smex_tree, hf_smex_mcs_num_error, tvb, offset, 1, FALSE); + proto_tree_add_item(smex_tree, hf_smex_data_inv, tvb, offset, 1, FALSE); + ++offset; + + proto_tree_add_item(smex_tree, hf_smex_frame_sync, tvb, offset, 1, FALSE); + proto_tree_add_item(smex_tree, hf_smex_data_dir, tvb, offset, 1, FALSE); + proto_tree_add_item(smex_tree, hf_smex_data_class, tvb, offset, 1, FALSE); + ++offset; + + /* extract smex ground receipt time tag */ + long_word = tvb_get_ntohl ( tvb, offset ); + pb5_days = ( long_word >> 17 ) & PB5_JULIAN_DAY_MASK; + pb5_seconds = ( long_word & PB5_SECONDS_MASK ); + + first_word = tvb_get_ntohs ( tvb, offset+4 ); + pb5_milliseconds = ( first_word & PB5_MILLISECONDS_MASK ) >> 6; + + proto_tree_add_item(smex_tree, hf_smex_pb5, tvb, offset, 2, FALSE); + proto_tree_add_item(smex_tree, hf_smex_jday, tvb, offset, 2, FALSE); + ++offset; + proto_tree_add_item(smex_tree, hf_smex_seconds, tvb, offset, 3, FALSE); + offset += 3; + + proto_tree_add_item(smex_tree, hf_smex_msec, tvb, offset, 2, FALSE); + /* proto_tree_add_item(smex_tree, hf_smex_spare, tvb, offset, 2, FALSE); */ + offset += 2; + + /* format ground receipt time into human readable time format for display */ + time_string = smex_time_to_string ( pb5_days, pb5_seconds, pb5_milliseconds ); + proto_tree_add_text (smex_tree, tvb, offset-6, 6, "%s = Ground Receipt Time", time_string ); + + proto_item_set_end(smex_header, tvb, offset); + + + /* build the vcdu header tree */ + vcdu_header=proto_tree_add_text(tree, tvb, offset, VCDU_HEADER_LENGTH, "VCDU Header"); + vcdu_tree = proto_item_add_subtree(vcdu_header, ett_vcdu); + + /* extract the virtual channel for use later on */ + first_word=tvb_get_ntohs(tvb, offset); + vcid = first_word & 0x3f; + + proto_tree_add_item(vcdu_tree, hf_vcdu_version, tvb, offset, 2, FALSE); + proto_tree_add_item(vcdu_tree, hf_vcdu_sp_id, tvb, offset, 2, FALSE); + proto_tree_add_item(vcdu_tree, hf_vcdu_vc_id, tvb, offset, 2, FALSE); + offset += 2; + proto_tree_add_item(vcdu_tree, hf_vcdu_seq, tvb, offset, 3, FALSE); + offset += 3; + proto_tree_add_item(vcdu_tree, hf_vcdu_replay, tvb, offset, 1, FALSE); + ++offset; + + /* extract mpdu/bpdu header word */ + first_word=tvb_get_ntohs(tvb, offset); + + /* do bitstream channel processing */ + if ( bitstream_channels[vcid] ) + { + /* extract last bit pointer for bitstream channels */ + new_ptr=first_word & LBP_MASK; + + /* add last bit pointer to display tree */ + proto_tree_add_item(vcdu_tree, hf_vcdu_lbp, tvb, offset, 2, FALSE); + + switch ( new_ptr ) + { + case LBP_ALL_DATA: + proto_tree_add_text(vcdu_tree, tvb, 0, -1, "Bitream ALL Data"); + break; + + case LBP_ALL_DATA_ANOMALY: + proto_tree_add_text(vcdu_tree, tvb, 0, -1, "Bitream ALL Data (Anomaly)"); + break; + + case LBP_ALL_FILL: + proto_tree_add_text(vcdu_tree, tvb, 0, -1, "Bitream ALL Fill"); + break; + + default: + break; + } + } /* end of bitstream channel processing */ + + /* do ccsds channel processing */ + else + { + /* extract first header pointer for ccsds channels */ + new_ptr=first_word & FHP_MASK; + + /* add first header pointer to display tree */ + proto_tree_add_item(vcdu_tree, hf_vcdu_fhp, tvb, offset, 2, FALSE); + + /* process special cases of first header pointer */ + if ( FHP_ALL_FILL == new_ptr ) + { + proto_tree_add_text(vcdu_tree, tvb, 0, -1, "Ccsds ALL Fill"); + } + + else if ( FHP_CONTINUATION == new_ptr ) + { + proto_tree_add_text(vcdu_tree, tvb, 0, -1, "Ccsds Continuation Packet"); + } + + /* process as many ccsds packet headers as we can using the ccsds packet dissector */ + else + { + /* compute offset and packet boundary lengths for ccsds dissector loop */ + new_offset=offset+2+new_ptr; + + packet_boundary = pinfo->iplen - IP_HEADER_LENGTH - VCDU_HEADER_LENGTH - CCSDS_PRIMARY_HEADER_LENGTH - CCSDS_SECONDARY_HEADER_LENGTH; + + while ( (new_offset-offset+2) < packet_boundary && (new_offset-offset+2) >= 4 ) + { + ccsds_tree_added = 1; + ccsds_len=tvb_get_ntohs(tvb, new_offset+4); + + apid=tvb_get_ntohs(tvb, new_offset); + apid=apid & 0x07ff; + /* printf ( "new_ptr=%d new_offset=%d apid=%d ccsds_len=%d\n", new_ptr, new_offset, apid, ccsds_len ); fflush(stdout); */ + + new_tvb = tvb_new_subset(tvb, new_offset, -1, -1); + g_assert(ccsds_handle != NULL); + call_dissector(ccsds_handle, new_tvb, pinfo, vcdu_tree); + + new_offset=new_offset+ccsds_len+7; + } + + if ( ! ccsds_tree_added ) + { + proto_tree_add_text(vcdu_tree, tvb, 0, -1, "FHP too close to end of VCDU. Incomplete Hdr Info Available - Unable to format CCSDS Hdr(s)." ); + } + } + + } /* end of ccsds channel processing */ + + /* don't include the mpdu/bpdu header in the vcdu header highlighting. + * by skipping the offset bump the vcdu header highlighting will show + * just 6 bytes as it really should, and the fhp/lbp will be included + * in the data zone, which is technically more correct. + */ + /* offset += 2; */ + proto_item_set_end(vcdu_tree, tvb, offset); + + if ( ! ccsds_tree_added ) + { + /* add "Data" section if ccsds parsing did not do so already */ + proto_tree_add_text(vcdu_tree, tvb, offset, -1, "Data"); + } + } +} + + +/* Register the protocol with Wireshark + * this format is require because a script is used to build the C function + * that calls all the protocol registration. + */ +void +proto_register_vcdu(void) +{ + /* Setup list of header fields See Section 1.6.1 for details*/ + static hf_register_info hf[] = { + { &hf_smex_gsc, + { "Ground Sequence Counter", "smex.gsc", + FT_UINT64, BASE_DEC, NULL, 0x0, + "SMEX Ground Sequence Counter", HFILL } + }, + { &hf_smex_unused, + { "Unused", "smex.unused", + FT_UINT16, BASE_DEC, NULL, 0x0, + "SMEX Unused", HFILL } + }, + { &hf_smex_version, + { "Version", "smex.version", + FT_UINT16, BASE_DEC, NULL, SMEX_VERSION, + "SMEX Version", HFILL } + }, + { &hf_smex_framelen, + { "Frame Length", "smex.frame_len", + FT_UINT16, BASE_DEC, NULL, SMEX_FRAMELEN, + "SMEX Frame Length", HFILL } + }, + { &hf_smex_rs_enable, + { "RS Enable", "smex.rs_enable", + FT_BOOLEAN, 8, NULL, 0x80, + "SMEX RS Enable", HFILL } + }, + { &hf_smex_rs_error, + { "RS Error", "smex.rs_error", + FT_BOOLEAN, 8, NULL, 0x40, + "SMEX RS Error", HFILL } + }, + { &hf_smex_crc_enable, + { "CRC Enable", "smex.crc_enable", + FT_BOOLEAN, 8, NULL, 0x20, + "SMEX CRC Enable", HFILL } + }, + { &hf_smex_crc_error, + { "CRC Error", "smex.crc_error", + FT_BOOLEAN, 8, NULL, 0x10, + "SMEX CRC Error", HFILL } + }, + { &hf_smex_mcs_enable, + { "MCS Enable", "smex.mcs_enable", + FT_BOOLEAN, 8, NULL, 0x08, + "SMEX MCS Enable", HFILL } + }, + { &hf_smex_mcs_num_error, + { "MCS Number Error", "smex.mcs_numerr", + FT_BOOLEAN, 8, NULL, 0x04, + "SMEX MCS Number Error", HFILL } + }, + { &hf_smex_data_inv, + { "Data Inversion", "smex.data_inv", + FT_UINT16, BASE_DEC, VALS(smex_data_inversion_type), 0x03, + "SMEX Data Inversion", HFILL } + }, + { &hf_smex_frame_sync, + { "Frame Sync", "smex.frame_sync", + FT_UINT16, BASE_DEC, VALS(smex_frame_sync_mode), 0xc0, + "SMEX Frame Sync Flag", HFILL } + }, + { &hf_smex_data_dir, + { "Data Direction", "smex.data_dir", + FT_UINT16, BASE_DEC, VALS(smex_data_direction), 0x20, + "SMEX Data Direction flag", HFILL } + }, + { &hf_smex_data_class, + { "Data Class", "smex.data_class", + FT_UINT16, BASE_DEC, VALS(smex_data_class), 0x1f, + "SMEX Data Class", HFILL } + }, + { &hf_smex_pb5, + { "PB5 Flag", "smex.pb5", + FT_UINT16, BASE_DEC, NULL, 0x8000, + "SMEX PB5 Flag", HFILL } + }, + { &hf_smex_jday, + { "Julian Day", "smex.jday", + FT_UINT16, BASE_DEC, NULL, PB5_JULIAN_DAY_MASK, + "SMEX Julian Day", HFILL } + }, + { &hf_smex_seconds, + { "Seconds", "smex.seconds", + FT_UINT24, BASE_DEC, NULL, PB5_SECONDS_MASK, + "SMEX Seconds", HFILL } + }, + { &hf_smex_msec, + { "Milliseconds", "smex.msec", + FT_UINT16, BASE_DEC, NULL, PB5_MILLISECONDS_MASK, + "SMEX Milliseconds", HFILL } + }, + { &hf_smex_spare, + { "Spare", "smex.spare", + FT_UINT16, BASE_DEC, NULL, 0x03f, + "SMEX Spare", HFILL } + }, + + + + { &hf_vcdu_version, + { "Version", "vcdu.version", + FT_UINT16, BASE_DEC, NULL, 0xc0, + "VCDU Version", HFILL } + }, + { &hf_vcdu_sp_id, + { "Space Craft ID", "vcdu.spid", + FT_UINT16, BASE_DEC, NULL, 0x3fc0, + "VCDU Space Craft ID", HFILL } + }, + { &hf_vcdu_vc_id, + { "Virtual Channel ID", "vcdu.vcid", + FT_UINT16, BASE_DEC, NULL, 0x3f, + "VCDU Virtual Channel ID", HFILL } + }, + { &hf_vcdu_seq, + { "Sequence Count", "vcdu.seq", + FT_UINT16, BASE_DEC, NULL, 0xffffff, + "VCDU Sequence Count", HFILL } + }, + { &hf_vcdu_replay, + { "Replay Flag", "vcdu.replay", + FT_BOOLEAN, 8, NULL, 0x80, + "VCDU Replay Flag", HFILL } + }, + + /* not really part of the vcdu header, but it's easier this way */ + { &hf_vcdu_fhp, + { "First Header Pointer", "vcdu.fhp", + FT_UINT16, BASE_DEC, NULL, FHP_MASK, + "VCDU/MPDU First Header Pointer", HFILL } + }, + { &hf_vcdu_lbp, + { "Last Bit Pointer", "vcdu.lbp", + FT_UINT16, BASE_DEC, NULL, LBP_MASK, + "VCDU/BPDU Last Bit Pointer", HFILL } + } + }; + + /* Setup protocol subtree array */ + static gint *ett[] = { + &ett_vcdu, + &ett_smex, + &ett_vcduh, + }; + + /* Register the protocol name and description */ + proto_vcdu = proto_register_protocol("VCDU", "VCDU", "vcdu"); + + /* Required function calls to register the header fields and subtrees used */ + proto_register_field_array(proto_vcdu, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + +} + + +/* If this dissector uses sub-dissector registration add a registration routine. + * This format is required because a script is used to find these routines and + * create the code that calls these routines. + */ +void +proto_reg_handoff_vcdu(void) +{ + register_dissector ( "vcdu", dissect_vcdu, proto_vcdu ); + dissector_add ( "udp.port", 0, find_dissector("vcdu") ); + ccsds_handle = find_dissector ( "ccsds" ); +} + |