/* Code to actually dissect the packets */ static void dissect_ccsds(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { int offset = 0; proto_item *ccsds_packet; proto_tree *ccsds_tree = NULL; proto_item *primary_header = NULL; proto_tree *primary_header_tree; guint16 first_word; guint32 coarse_time; guint8 fine_time; proto_item *secondary_header; proto_tree *secondary_header_tree; const char* time_string; gint ccsds_length; gint length = 0; gint reported_length; guint8 checkword_flag = 0; gint counter = 0; proto_item *item = NULL; proto_tree *checkword_tree; guint16 checkword_field = 0; guint16 checkword_sum = 0; col_set_str(pinfo->cinfo, COL_PROTOCOL, "CCSDS"); col_set_str(pinfo->cinfo, COL_INFO, "CCSDS Packet"); first_word=tvb_get_ntohs(tvb, 0); col_add_fstr(pinfo->cinfo, COL_INFO, "APID %1$4d (0x%1$03X)", first_word&HDR_APID); reported_length = tvb_reported_length_remaining(tvb, 0); ccsds_length = tvb_get_ntohs(tvb, 4) + CCSDS_PRIMARY_HEADER_LENGTH + 1; if (tree) { /* Min length is size of headers, whereas max length is reported length. * If the length field in the CCSDS header is outside of these bounds, * use the value it violates. Otherwise, use the length field value. */ if (ccsds_length > reported_length) length = reported_length; else if (ccsds_length < CCSDS_PRIMARY_HEADER_LENGTH + CCSDS_SECONDARY_HEADER_LENGTH) length = CCSDS_PRIMARY_HEADER_LENGTH + CCSDS_SECONDARY_HEADER_LENGTH; else length = ccsds_length; ccsds_packet = proto_tree_add_item(tree, proto_ccsds, tvb, 0, length, ENC_NA); 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); 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(primary_header_tree, hf_ccsds_seqflag, tvb, offset, 2, ENC_BIG_ENDIAN); proto_tree_add_item(primary_header_tree, hf_ccsds_seqnum, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; item = proto_tree_add_item(primary_header_tree, hf_ccsds_length, tvb, offset, 2, ENC_BIG_ENDIAN); } if (ccsds_length > reported_length) { expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR, "Length field value is greater than the packet seen on the wire"); } if (tree) { offset += 2; proto_item_set_end(primary_header, tvb, offset); /* build the ccsds secondary header tree */ if ( first_word & HDR_SECHDR ) { 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); /* 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, ENC_BIG_ENDIAN); offset += 4; fine_time=tvb_get_guint8(tvb, offset); proto_tree_add_item(secondary_header_tree, hf_ccsds_fine_time, tvb, offset, 1, ENC_BIG_ENDIAN); ++offset; 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(secondary_header_tree, hf_ccsds_timeid, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(secondary_header_tree, hf_ccsds_checkword_flag, tvb, offset, 1, ENC_BIG_ENDIAN); /* Global Preference: how to handle checkword flag */ switch (global_dissect_checkword) { case 0: /* force checkword presence flag to be false */ checkword_flag = 0; break; case 1: /* force checkword presence flag to be true */ checkword_flag = 1; break; default: /* use value of checkword presence flag from header */ checkword_flag = (tvb_get_guint8(tvb, offset)&0x20) >> 5; break; } /* payload specific ccsds secondary header flags */ if ( first_word & HDR_TYPE ) { proto_tree_add_item(secondary_header_tree, hf_ccsds_zoe, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(secondary_header_tree, hf_ccsds_packet_type_unused, tvb, offset, 1, ENC_BIG_ENDIAN); ++offset; proto_tree_add_item(secondary_header_tree, hf_ccsds_vid, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item(secondary_header_tree, hf_ccsds_dcc, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; } /* core specific ccsds secondary header flags */ else { /* proto_tree_add_item(secondary_header_tree, hf_ccsds_spare1, tvb, offset, 1, ENC_BIG_ENDIAN); */ proto_tree_add_item(secondary_header_tree, hf_ccsds_packet_type, tvb, offset, 1, ENC_BIG_ENDIAN); ++offset; /* proto_tree_add_item(secondary_header_tree, hf_ccsds_spare2, tvb, offset, 2, ENC_BIG_ENDIAN); */ proto_tree_add_item(secondary_header_tree, hf_ccsds_element_id, tvb, offset, 2, ENC_BIG_ENDIAN); proto_tree_add_item(secondary_header_tree, hf_ccsds_cmd_data_packet, tvb, offset, 2, ENC_BIG_ENDIAN); proto_tree_add_item(secondary_header_tree, hf_ccsds_format_version_id, tvb, offset, 2, ENC_BIG_ENDIAN); proto_tree_add_item(secondary_header_tree, hf_ccsds_extended_format_id, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; /* proto_tree_add_item(secondary_header_tree, hf_ccsds_spare3, tvb, offset, 1, ENC_BIG_ENDIAN); */ ++offset; proto_tree_add_item(secondary_header_tree, hf_ccsds_frame_id, tvb, offset, 1, ENC_BIG_ENDIAN); ++offset; } /* finish the ccsds secondary header */ proto_item_set_end(secondary_header, tvb, offset); } /* If there wasn't a full packet, then don't allow a tree item for checkword. */ if (reported_length < ccsds_length || ccsds_length < CCSDS_PRIMARY_HEADER_LENGTH + CCSDS_SECONDARY_HEADER_LENGTH) { /* Label CCSDS payload 'User Data' */ if (length > offset) proto_tree_add_text(ccsds_tree, tvb, offset, length-offset, "User Data"); offset += length-offset; if (checkword_flag == 1) proto_tree_add_text(ccsds_tree, tvb, offset, 0, "Packet does not contain a Checkword"); } /* Handle checkword according to CCSDS preference setting. */ else { /* Label CCSDS payload 'User Data' */ proto_tree_add_text(ccsds_tree, tvb, offset, length-offset-2*checkword_flag, "User Data"); offset += length-offset-2*checkword_flag; /* If checkword is present, calculate packet checksum (16-bit running sum) for comparison */ if (checkword_flag == 1) { /* don't count the checkword as part of the checksum */ while (counter < ccsds_length-2) { checkword_sum += tvb_get_ntohs(tvb, counter); counter += 2; } checkword_field = tvb_get_ntohs(tvb, offset); /* Report checkword status */ if (checkword_sum == checkword_field) { item = proto_tree_add_uint_format(ccsds_tree, hf_ccsds_checkword, tvb, offset, 2, checkword_field, "CCSDS checkword: 0x%04x [correct]", checkword_field); checkword_tree = proto_item_add_subtree(item, ett_ccsds_checkword); item = proto_tree_add_boolean(checkword_tree, hf_ccsds_checkword_good, tvb, offset, 2, TRUE); PROTO_ITEM_SET_GENERATED(item); item = proto_tree_add_boolean(checkword_tree, hf_ccsds_checkword_bad, tvb, offset, 2, FALSE); PROTO_ITEM_SET_GENERATED(item); } else { item = proto_tree_add_uint_format(ccsds_tree, hf_ccsds_checkword, tvb, offset, 2, checkword_field, "CCSDS checkword: 0x%04x [incorrect, should be 0x%04x]", checkword_field, checkword_sum); checkword_tree = proto_item_add_subtree(item, ett_ccsds_checkword); item = proto_tree_add_boolean(checkword_tree, hf_ccsds_checkword_good, tvb, offset, 2, FALSE); PROTO_ITEM_SET_GENERATED(item); item = proto_tree_add_boolean(checkword_tree, hf_ccsds_checkword_bad, tvb, offset, 2, TRUE); PROTO_ITEM_SET_GENERATED(item); } offset += 2; } } /* Give the data dissector any bytes past the CCSDS packet length */ /* (XXX: Not really OK under 'if (tree)' but will work; see packet-data.c */ call_dissector(data_handle, tvb_new_subset_remaining(tvb, offset), pinfo, tree); } /* if(tree) */
/* Code to actually dissect the packets */ static void dissect_ccsds(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { int offset = 0; proto_item *ccsds_packet; proto_tree *ccsds_tree; proto_item *primary_header; proto_tree *primary_header_tree; guint16 first_word; guint32 coarse_time; guint8 fine_time; proto_item *secondary_header; proto_tree *secondary_header_tree; const char *time_string; gint ccsds_length; gint length = 0; gint reported_length; guint8 checkword_flag = 0; gint counter = 0; proto_item *item, *checkword_item = NULL; proto_tree *checkword_tree; guint16 checkword_field = 0; guint16 checkword_sum = 0; tvbuff_t *next_tvb; static const int * header_flags[] = { &hf_ccsds_version, &hf_ccsds_type, &hf_ccsds_secheader, &hf_ccsds_apid, NULL }; col_set_str(pinfo->cinfo, COL_PROTOCOL, "CCSDS"); col_set_str(pinfo->cinfo, COL_INFO, "CCSDS Packet"); first_word = tvb_get_ntohs(tvb, 0); col_add_fstr(pinfo->cinfo, COL_INFO, "APID %4d (0x%03X)", first_word&HDR_APID, first_word&HDR_APID); reported_length = tvb_reported_length_remaining(tvb, 0); ccsds_length = tvb_get_ntohs(tvb, 4) + CCSDS_PRIMARY_HEADER_LENGTH + 1; /* Min length is size of headers, whereas max length is reported length. * If the length field in the CCSDS header is outside of these bounds, * use the value it violates. Otherwise, use the length field value. */ if (ccsds_length > reported_length) length = reported_length; else if (ccsds_length < CCSDS_PRIMARY_HEADER_LENGTH + CCSDS_SECONDARY_HEADER_LENGTH) length = CCSDS_PRIMARY_HEADER_LENGTH + CCSDS_SECONDARY_HEADER_LENGTH; else length = ccsds_length; ccsds_packet = proto_tree_add_item(tree, proto_ccsds, tvb, 0, length, ENC_NA); ccsds_tree = proto_item_add_subtree(ccsds_packet, ett_ccsds); /* build the ccsds primary header tree */ primary_header_tree = proto_tree_add_subtree(ccsds_tree, tvb, offset, CCSDS_PRIMARY_HEADER_LENGTH, ett_ccsds_primary_header, &primary_header, "Primary CCSDS Header"); proto_tree_add_bitmask(primary_header_tree, tvb, offset, hf_ccsds_header_flags, ett_ccsds_primary_header_flags, header_flags, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item(primary_header_tree, hf_ccsds_seqflag, tvb, offset, 2, ENC_BIG_ENDIAN); proto_tree_add_item(primary_header_tree, hf_ccsds_seqnum, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; item = proto_tree_add_item(primary_header_tree, hf_ccsds_length, tvb, offset, 2, ENC_BIG_ENDIAN); if (ccsds_length > reported_length) { expert_add_info(pinfo, item, &ei_ccsds_length_error); } offset += 2; proto_item_set_end(primary_header, tvb, offset); /* build the ccsds secondary header tree */ if ( first_word & HDR_SECHDR ) { secondary_header_tree = proto_tree_add_subtree(ccsds_tree, tvb, offset, CCSDS_SECONDARY_HEADER_LENGTH, ett_ccsds_secondary_header, &secondary_header, "Secondary CCSDS Header"); /* 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, ENC_BIG_ENDIAN); offset += 4; fine_time = tvb_get_guint8(tvb, offset); proto_tree_add_item(secondary_header_tree, hf_ccsds_fine_time, tvb, offset, 1, ENC_BIG_ENDIAN); ++offset; time_string = embedded_time_to_string ( coarse_time, fine_time ); proto_tree_add_string(secondary_header_tree, hf_ccsds_embedded_time, tvb, offset-5, 5, time_string); proto_tree_add_item(secondary_header_tree, hf_ccsds_timeid, tvb, offset, 1, ENC_BIG_ENDIAN); checkword_item = proto_tree_add_item(secondary_header_tree, hf_ccsds_checkword_flag, tvb, offset, 1, ENC_BIG_ENDIAN); /* Global Preference: how to handle checkword flag */ switch (global_dissect_checkword) { case 0: /* force checkword presence flag to be false */ checkword_flag = 0; break; case 1: /* force checkword presence flag to be true */ checkword_flag = 1; break; default: /* use value of checkword presence flag from header */ checkword_flag = (tvb_get_guint8(tvb, offset)&0x20) >> 5; break; } /* payload specific ccsds secondary header flags */ if ( first_word & HDR_TYPE ) { proto_tree_add_item(secondary_header_tree, hf_ccsds_zoe, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(secondary_header_tree, hf_ccsds_packet_type_unused, tvb, offset, 1, ENC_BIG_ENDIAN); ++offset; proto_tree_add_item(secondary_header_tree, hf_ccsds_vid, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item(secondary_header_tree, hf_ccsds_dcc, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; } /* core specific ccsds secondary header flags */ else { /* proto_tree_add_item(secondary_header_tree, hf_ccsds_spare1, tvb, offset, 1, ENC_BIG_ENDIAN); */ proto_tree_add_item(secondary_header_tree, hf_ccsds_packet_type, tvb, offset, 1, ENC_BIG_ENDIAN); ++offset; /* proto_tree_add_item(secondary_header_tree, hf_ccsds_spare2, tvb, offset, 2, ENC_BIG_ENDIAN); */ proto_tree_add_item(secondary_header_tree, hf_ccsds_element_id, tvb, offset, 2, ENC_BIG_ENDIAN); proto_tree_add_item(secondary_header_tree, hf_ccsds_cmd_data_packet, tvb, offset, 2, ENC_BIG_ENDIAN); proto_tree_add_item(secondary_header_tree, hf_ccsds_format_version_id, tvb, offset, 2, ENC_BIG_ENDIAN); proto_tree_add_item(secondary_header_tree, hf_ccsds_extended_format_id, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; /* proto_tree_add_item(secondary_header_tree, hf_ccsds_spare3, tvb, offset, 1, ENC_BIG_ENDIAN); */ ++offset; proto_tree_add_item(secondary_header_tree, hf_ccsds_frame_id, tvb, offset, 1, ENC_BIG_ENDIAN); ++offset; } /* finish the ccsds secondary header */ proto_item_set_end(secondary_header, tvb, offset); }