wireshark/epan/dissectors/packet-cfdp.c
Michael Mann 2eb7b05b8c Convert most UDP dissectors to use "auto" preferences.
Similar to the "tcp.port" changes in I99604f95d426ad345f4b494598d94178b886eb67,
convert dissectors that use "udp.port".

More cleanup done on dissectors that use both TCP and UDP dissector
tables, so that less preference callbacks exist.

Change-Id: If07be9b9e850c244336a7069599cd554ce312dd3
Reviewed-on: https://code.wireshark.org/review/18120
Petri-Dish: Michael Mann <mmann78@netscape.net>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Michael Mann <mmann78@netscape.net>
2016-10-13 02:51:18 +00:00

1649 lines
60 KiB
C

/* packet-cfdp.c
* Routines for CCSDS File Delivery Protocol (CFDP) dissection
* Copyright 2013, Juan Antonio Montesinos juan.mondl@gmail.com
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include <epan/packet.h>
#include <epan/expert.h>
/* The CFDP standard can be found here:
* http://public.ccsds.org/publications/archive/727x0b4.pdf
*
* The Store and Forward Overlay Operations are not included.
*/
void proto_register_cfdp(void);
void proto_reg_handoff_cfdp(void);
/* Initialize the protocol and registered fields */
static int proto_cfdp = -1;
static int hf_cfdp_version = -1;
static int hf_cfdp_pdu_type = -1;
static int hf_cfdp_direction = -1;
static int hf_cfdp_trans_mode = -1;
static int hf_cfdp_crc_flag = -1;
static int hf_cfdp_res1 = -1;
static int hf_cfdp_data_length = -1;
static int hf_cfdp_res2 = -1;
static int hf_cfdp_entid_length = -1;
static int hf_cfdp_res3 = -1;
static int hf_cfdp_transeqnum_length = -1;
static int hf_cfdp_srcid = -1;
static int hf_cfdp_transeqnum = -1;
static int hf_cfdp_dstid = -1;
static int hf_cfdp_file_directive_type = -1;
static int hf_cfdp_file_data_offset = -1;
static int hf_cfdp_progress = -1;
static int hf_cfdp_dir_code_ack = -1;
static int hf_cfdp_dir_subtype_ack = -1;
static int hf_cfdp_condition_code = -1;
static int hf_cfdp_spare_one = -1;
static int hf_cfdp_spare_one_2 = -1;
static int hf_cfdp_spare_two = -1;
static int hf_cfdp_spare_four = -1;
static int hf_cfdp_spare_five = -1;
static int hf_cfdp_spare_seven = -1;
static int hf_cfdp_spare_seven_2 = -1;
static int hf_cfdp_trans_stat_ack = -1;
static int hf_cfdp_file_checksum = -1;
static int hf_cfdp_file_size = -1;
static int hf_cfdp_end_system_stat = -1;
static int hf_cfdp_delivery_code = -1;
static int hf_cfdp_file_stat = -1;
static int hf_cfdp_segment_control = -1;
static int hf_cfdp_src_file_name = -1;
static int hf_cfdp_dst_file_name = -1;
static int hf_cfdp_first_file_name = -1;
static int hf_cfdp_second_file_name = -1;
static int hf_cfdp_nak_st_scope = -1;
static int hf_cfdp_nak_sp_scope = -1;
static int hf_cfdp_crc = -1;
static int hf_cfdp_action_code = -1;
static int hf_cfdp_status_code_1 = -1;
static int hf_cfdp_status_code_2 = -1;
static int hf_cfdp_status_code_3 = -1;
static int hf_cfdp_status_code_4 = -1;
static int hf_cfdp_status_code_5 = -1;
static int hf_cfdp_status_code_6 = -1;
static int hf_cfdp_status_code_7 = -1;
static int hf_cfdp_status_code_8 = -1;
static int hf_cfdp_handler_code = -1;
static int hf_cfdp_trans_mode_msg = -1;
static int hf_cfdp_proxy_msg_type = -1;
static int hf_cfdp_proxy_segment_control = -1;
static int hf_cfdp_proxy_delivery_code = -1;
static int hf_cfdp_response_req = -1;
static int hf_cfdp_directory_name = -1;
static int hf_cfdp_directory_file_name = -1;
static int hf_cfdp_listing_resp_code = -1;
static int hf_cfdp_report_file_name = -1;
static int hf_cfdp_trans_stat = -1;
static int hf_cfdp_trans_stat_2 = -1;
static int hf_cfdp_rep_resp_code = -1;
static int hf_cfdp_suspension_ind = -1;
static int hf_cfdp_tlv_len = - 1;
/* Generated from convert_proto_tree_add_text.pl */
static int hf_cfdp_filestore_message = -1;
static int hf_cfdp_entity = -1;
static int hf_cfdp_message_to_user = -1;
static int hf_cfdp_flow_label = -1;
static int hf_cfdp_segment_requests = -1;
static int hf_cfdp_user_data = -1;
/* Initialize the subtree pointers */
static gint ett_cfdp = -1;
static gint ett_cfdp_header = -1;
static gint ett_cfdp_file_directive_header = -1;
static gint ett_cfdp_file_data_header = -1;
static gint ett_cfdp_fault_location = -1;
static gint ett_cfdp_crc = -1;
static gint ett_cfdp_filestore_req = -1;
static gint ett_cfdp_filestore_resp = -1;
static gint ett_cfdp_msg_to_user = -1;
static gint ett_cfdp_fault_hdl_overr = -1;
static gint ett_cfdp_flow_label = -1;
static expert_field ei_cfdp_bad_length = EI_INIT;
static dissector_handle_t cfdp_handle;
/* Some parameters */
#define CFDP_HEADER_FIXED_FIELDS_LEN 4
#define CFDP_APID 2045
/* Bitmask for the first byte of the Header */
#define HDR_VERSION_CFDP 0xe0
#define HDR_TYPE_CFDP 0x10
#define HDR_DIR 0x08
#define HDR_TMODE 0x04
#define HDR_CRCF 0x02
#define HDR_RES1 0x01
/* Bitmask for the second byte of the Header */
#define HDR_RES2 0x80
#define HDR_LEN_ENT_ID 0x70
#define HDR_RES3 0x08
#define HDR_LEN_TSEQ_NUM 0x07
/* File Directive Codes */
#define EOF_PDU 4
#define FINISHED_PDU 5
#define ACK_PDU 6
#define METADATA_PDU 7
#define NAK_PDU 8
#define PROMPT_PDU 9
#define KEEP_ALIVE_PDU 12
/* TLV Types */
#define FILESTORE_REQ 0
#define FILESTORE_RESP 1
#define MSG_TO_USER 2
#define FAULT_HDL_OVERR 4
#define FLOW_LABEL 5
#define FAULT_LOCATION 6
/* ID for reserved CFDP Messages */
#define CFDP_MSG_TO_USER 0x63666470
/* Proxy Operations Message Types */
#define PROXY_PUT_REQ 0x00
#define PROXY_MSG_TO_USER 0x01
#define PROXY_FILESTORE_REQ 0x02
#define PROXY_FAULT_HDL_OVERR 0x03
#define PROXY_TRANS_MODE 0x04
#define PROXY_FLOW_LABEL 0x05
#define PROXY_SEGMENT_CONTROL 0x06
#define PROXY_PUT_RESP 0x07
#define PROXY_FILESTORE_RESP 0x08
#define PROXY_PUT_CANCEL 0x09
#define ORIG_TRANS_ID 0x0A
#define DIRECTORY_LIST_REQ 0x10
#define DIRECTORY_LIST_RESP 0x11
#define REMOTE_STAT_REP_REQ 0x20
#define REMOTE_STAT_REP_RESP 0x21
#define REMOTE_SUSPEND_REQ 0x30
#define REMOTE_SUSPEND_RESP 0x31
#define REMOTE_RESUME_REQ 0x38
#define REMOTE_RESUME_RESP 0x39
/* PDU Type */
static const value_string cfdp_pdu_type[] = {
{ 0, "File Directive" },
{ 1, "File Data" },
{ 0, NULL }
};
/* PDU Direction */
static const value_string cfdp_direction[] = {
{ 0, "Toward file receiver" },
{ 1, "Toward file sender" },
{ 0, NULL }
};
/* Transmission mode */
static const value_string cfdp_trans_mode[] = {
{ 0, "Acknowledged" },
{ 1, "Unacknowledged" },
{ 0, NULL }
};
/* CRC */
static const value_string cfdp_crc_flag[] = {
{ 0, "CRC not present" },
{ 1, "CRC present" },
{ 0, NULL }
};
/* File Directive PDU Type */
static const value_string cfdp_file_directive_type[] = {
{ 4, "EOF PDU"},
{ 5, "Finished PDU"},
{ 6, "ACK PDU"},
{ 7, "Metadata PDU"},
{ 8, "NACK PDU"},
{ 9, "Prompt PDU"},
{ 12, "Keep Alive PDU"},
{ 0, NULL}
};
/* Condition codes */
static const value_string cfdp_condition_codes[] = {
{ 0, "No error"},
{ 1, "Positive ACK limit reached"},
{ 2, "Keep alive limit reached"},
{ 3, "Invalid transmission mode"},
{ 4, "Filestore rejection"},
{ 5, "File checksum failure"},
{ 6, "File size error"},
{ 7, "NAK limit reached"},
{ 8, "Inactivity detected"},
{ 9, "Check limit reached"},
{ 14, "Suspend.request received"},
{ 15, "Cancel.request received"},
{ 0, NULL }
};
/* Transaction status */
static const value_string cfdp_trans_stat_ack[] = {
{ 0, "Undefined" },
{ 1, "Active" },
{ 2, "Terminated" },
{ 3, "Unrecognized" },
{ 0, NULL }
};
/* End system status */
static const value_string cfdp_end_system_stat[] = {
{ 0, "Generated by Waypoint" },
{ 1, "Generated by End System" },
{ 0, NULL }
};
/* Delivery code */
static const value_string cfdp_delivery_code[] = {
{ 0, "Data Complete" },
{ 1, "Data incomplete" },
{ 0, NULL }
};
/* Filestore operations action code */
static const value_string cfdp_action_code[] = {
{ 0, "Create File" },
{ 1, "Delete File" },
{ 2, "Rename File" },
{ 3, "Append File" },
{ 4, "Replace File" },
{ 5, "Create Directory" },
{ 6, "Remove Directory" },
{ 7, "Deny File (delete if present)" },
{ 8, "Deny Directory (remove if present)" },
{ 0, NULL }
};
/* Filestore operations status codes */
static const value_string cfdp_status_code_1[] = {
{ 0, "Successful" },
{ 1, "Create not allowed" },
{ 8, "Not performed" },
{ 0, NULL }
};
static const value_string cfdp_status_code_2[] = {
{ 0, "Successful" },
{ 1, "File does not exist" },
{ 2, "Delete not allowed" },
{ 8, "Not performed" },
{ 0, NULL }
};
static const value_string cfdp_status_code_3[] = {
{ 0, "Successful" },
{ 1, "Old File Name does not exist" },
{ 2, "New File Name already exists" },
{ 3, "Rename not allowed" },
{ 8, "Not performed" },
{ 0, NULL }
};
static const value_string cfdp_status_code_4[] = {
{ 0, "Successful" },
{ 1, "File Name 1 does not exist" },
{ 2, "File Name 2 does not exist" },
{ 3, "Append not allowed" },
{ 8, "Not performed" },
{ 0, NULL }
};
static const value_string cfdp_status_code_5[] = {
{ 0, "Successful" },
{ 1, "File Name 1 does not exist" },
{ 2, "File Name 2 does not exist" },
{ 3, "Replace not allowed" },
{ 8, "Not performed" },
{ 0, NULL }
};
static const value_string cfdp_status_code_6[] = {
{ 0, "Successful" },
{ 1, "Directory cannot be created" },
{ 8, "Not performed" },
{ 0, NULL }
};
static const value_string cfdp_status_code_7[] = {
{ 0, "Successful" },
{ 1, "Directory does not exist" },
{ 2, "Delete not allowed" },
{ 8, "Not performed" },
{ 0, NULL }
};
static const value_string cfdp_status_code_8[] = {
{ 0, "Successful" },
{ 1, "Delete not allowed" },
{ 8, "Not performed" },
{ 0, NULL }
};
/* Finished PDU File Status */
static const value_string cfdp_file_stat[] = {
{ 0, "Delivery file discarded deliberately" },
{ 1, "Delivery file discarded due to filestore rejection" },
{ 2, "Delivery file retained in filestore successfully" },
{ 3, "Delivery file status unreported" },
{ 0, NULL }
};
/* Segmentation control */
static const value_string cfdp_segment_control[] = {
{ 0, "Record boundaries respected" },
{ 1, "Record boundaries not respected" },
{ 0, NULL }
};
/* Fault handler override Handler code*/
static const value_string cfdp_handler_codes[] = {
{ 1, "issue Notice of Cancellation" },
{ 2, "issue Notice of Suspension" },
{ 3, "Ignore error" },
{ 4, "Abandon transaction" },
{ 0, NULL }
};
/* Type of Proxy message */
static const value_string cfdp_proxy_msg_type[] = {
{ 0x00, "Proxy Put Request"},
{ 0x01, "Proxy Message To User"},
{ 0x02, "Proxy Filestore Request"},
{ 0x03, "Proxy Fault Handler Override"},
{ 0x04, "Proxy Transmission Mode"},
{ 0x05, "Proxy Flow Label"},
{ 0x06, "Proxy Segmentation Control"},
{ 0x07, "Proxy Put Response"},
{ 0x08, "Proxy Filestore Response"},
{ 0x09, "Proxy Put Cancel"},
{ 0x0A, "Originating Transaction ID"},
{ 0x10, "Directory Listing Request"},
{ 0x11, "Directory Listing Response"},
{ 0x20, "Remote Status Report Request"},
{ 0x21, "Remote Status Report Response"},
{ 0x30, "Remote Suspend Request"},
{ 0x31, "Remote Suspend Response"},
{ 0x38, "Remote Resume Request"},
{ 0x39, "Remote Resume Response"},
{ 0, NULL }
};
static value_string_ext cfdp_proxy_msg_type_ext = VALUE_STRING_EXT_INIT(cfdp_proxy_msg_type);
/* Prompt PDU Response required */
static const value_string cfdp_response_req[] = {
{ 0, "NAK" },
{ 1, "Keep Alive" },
{ 0, NULL }
};
/* Listing response code */
static const value_string cfdp_listing_resp_code[] = {
{ 0, "Successful" },
{ 1, "Unsuccessful" },
{ 0, NULL }
};
/* Report response code */
static const value_string cfdp_rep_resp_code[] = {
{ 0, "Unsuccessful" },
{ 1, "Successful" },
{ 0, NULL }
};
/* Suspension indication */
static const value_string cfdp_suspension_ind[] = {
{ 0, "Not Suspended" },
{ 1, "Suspended" },
{ 0, NULL }
};
/* File Directive codes */
static const value_string cfdp_directive_codes[] = {
{ 0x04, "EOF" },
{ 0x05, "Finished" },
{ 0x06, "ACK" },
{ 0x07, "Metadata" },
{ 0x08, "NAK" },
{ 0x09, "Prompt" },
{ 0x0C, "Keep Alive" },
{ 0, NULL }
};
/* Dissect the Source Entity ID field */
static void
dissect_cfdp_src_entity_id(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset, guint8 len_ent_id)
{
if(len_ent_id > 0 && len_ent_id <= 8){
proto_tree_add_item(tree, hf_cfdp_srcid, tvb, offset, len_ent_id, ENC_BIG_ENDIAN);
}
else{
proto_tree_add_expert_format(tree, pinfo, &ei_cfdp_bad_length, tvb, offset, 0, "Wrong length for the entity ID");
}
}
/* Dissect the Destination Entity ID field */
static void
dissect_cfdp_dst_entity_id(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset, guint8 len_ent_id)
{
if(len_ent_id > 0 && len_ent_id <= 8){
proto_tree_add_item(tree, hf_cfdp_dstid, tvb, offset, len_ent_id, ENC_BIG_ENDIAN);
}
else{
proto_tree_add_expert_format(tree, pinfo, &ei_cfdp_bad_length, tvb, offset, 0, "Wrong length for the entity ID");
}
}
/* Dissect the Transaction Sequence Number field */
static void
dissect_cfdp_tseq_num(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset, guint8 len_tseq_num)
{
if(len_tseq_num > 0 && len_tseq_num <= 8){
proto_tree_add_item(tree, hf_cfdp_transeqnum, tvb, offset, len_tseq_num, ENC_BIG_ENDIAN);
}
else{
proto_tree_add_expert_format(tree, pinfo, &ei_cfdp_bad_length, tvb, offset, 0, "Wrong length for transaction sequence number");
}
}
/* Dissect the Filestore Request TLV */
static guint32 dissect_cfdp_filestore_req_tlv(tvbuff_t *tvb, proto_tree *tree, guint32 ext_offset){
guint8 tlv_len;
guint32 offset = ext_offset;
/* Get field length */
tlv_len = tvb_get_guint8(tvb, offset);
offset += 1;
if(tlv_len > 0){
proto_tree *cfdp_filestore_req_tree;
guint8 aux_byte;
/* Create a TLV subtree */
cfdp_filestore_req_tree = proto_tree_add_subtree(tree, tvb, offset-2, tlv_len+2,
ett_cfdp_filestore_req, NULL, "Filestore Request TLV");
proto_tree_add_uint(cfdp_filestore_req_tree, hf_cfdp_tlv_len, tvb, offset-1, 1, tlv_len);
aux_byte = tvb_get_guint8(tvb, offset);
proto_tree_add_uint(cfdp_filestore_req_tree, hf_cfdp_action_code, tvb, offset, 1, aux_byte);
proto_tree_add_uint(cfdp_filestore_req_tree, hf_cfdp_spare_four, tvb, offset, 1, aux_byte);
offset += 1;
aux_byte = tvb_get_guint8(tvb, offset);
offset += 1;
proto_tree_add_item(cfdp_filestore_req_tree, hf_cfdp_first_file_name, tvb, offset, aux_byte, ENC_ASCII|ENC_NA);
offset += aux_byte;
aux_byte = tvb_get_guint8(tvb, offset);
offset += 1;
if(aux_byte > 0){
proto_tree_add_item(cfdp_filestore_req_tree, hf_cfdp_second_file_name, tvb, offset, aux_byte, ENC_ASCII|ENC_NA);
offset += aux_byte;
}
}
return offset;
}
/* Dissect the Filestore Response TLV */
static guint32 dissect_cfdp_filestore_resp_tlv(tvbuff_t *tvb, proto_tree *tree, guint32 ext_offset){
guint8 tlv_len;
guint32 offset = ext_offset;
/* Get field length */
tlv_len = tvb_get_guint8(tvb, offset);
offset += 1;
if(tlv_len > 0){
proto_tree *cfdp_filestore_resp_tree;
guint8 aux_byte;
/* Create a subtree */
cfdp_filestore_resp_tree = proto_tree_add_subtree(tree, tvb, offset-2, tlv_len+2,
ett_cfdp_filestore_resp, NULL, "Filestore Response TLV");
proto_tree_add_uint(cfdp_filestore_resp_tree, hf_cfdp_tlv_len, tvb, offset-1, 1, tlv_len);
aux_byte = tvb_get_guint8(tvb, offset);
proto_tree_add_uint(cfdp_filestore_resp_tree, hf_cfdp_action_code, tvb, offset, 1, aux_byte);
switch((aux_byte & 0xF0) >> 4){
case 0:
proto_tree_add_uint(cfdp_filestore_resp_tree, hf_cfdp_status_code_1, tvb, offset, 1, aux_byte);
break;
case 1:
proto_tree_add_uint(cfdp_filestore_resp_tree, hf_cfdp_status_code_2, tvb, offset, 1, aux_byte);
break;
case 2:
proto_tree_add_uint(cfdp_filestore_resp_tree, hf_cfdp_status_code_3, tvb, offset, 1, aux_byte);
break;
case 3:
proto_tree_add_uint(cfdp_filestore_resp_tree, hf_cfdp_status_code_4, tvb, offset, 1, aux_byte);
break;
case 4:
proto_tree_add_uint(cfdp_filestore_resp_tree, hf_cfdp_status_code_5, tvb, offset, 1, aux_byte);
break;
case 5:
proto_tree_add_uint(cfdp_filestore_resp_tree, hf_cfdp_status_code_6, tvb, offset, 1, aux_byte);
break;
case 6:
proto_tree_add_uint(cfdp_filestore_resp_tree, hf_cfdp_status_code_7, tvb, offset, 1, aux_byte);
break;
case 7: case 8:
proto_tree_add_uint(cfdp_filestore_resp_tree, hf_cfdp_status_code_8, tvb, offset, 1, aux_byte);
break;
default:
break;
}
offset += 1;
aux_byte = tvb_get_guint8(tvb, offset);
offset += 1;
proto_tree_add_item(cfdp_filestore_resp_tree, hf_cfdp_first_file_name, tvb, offset, aux_byte, ENC_ASCII|ENC_NA);
offset += aux_byte;
aux_byte = tvb_get_guint8(tvb, offset);
offset += 1;
if(aux_byte > 0){
proto_tree_add_item(cfdp_filestore_resp_tree, hf_cfdp_second_file_name, tvb, offset, aux_byte, ENC_ASCII|ENC_NA);
offset += aux_byte;
}
/* Filestore Message */
aux_byte = tvb_get_guint8(tvb, offset);
offset += 1;
if(aux_byte > 0){
proto_tree_add_item(cfdp_filestore_resp_tree, hf_cfdp_filestore_message, tvb, offset, tlv_len, ENC_NA);
offset += aux_byte;
}
}
return offset;
}
/* Dissect the Fault Location TLV */
static guint32 dissect_cfdp_fault_location_tlv(tvbuff_t *tvb, proto_tree *tree, guint32 ext_offset){
guint8 tlv_len;
guint32 offset = ext_offset;
/* Get field length */
tlv_len = tvb_get_guint8(tvb, offset);
offset += 1;
if(tlv_len > 0){
proto_tree *cfdp_fault_location_tree;
/* Create a subtree */
cfdp_fault_location_tree = proto_tree_add_subtree(tree, tvb, offset-2, tlv_len+2,
ett_cfdp_fault_location, NULL, "Fault location TLV");
proto_tree_add_uint(cfdp_fault_location_tree, hf_cfdp_tlv_len, tvb, offset-1, 1, tlv_len);
proto_tree_add_item(cfdp_fault_location_tree, hf_cfdp_entity, tvb, offset, tlv_len, ENC_NA);
offset += tlv_len;
}
return offset;
}
/* Dissect the Message to User TLV */
static guint32 dissect_cfdp_msg_to_user_tlv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 ext_offset){
guint8 aux_byte, tlv_type, tlv_len;
proto_tree *cfdp_msg_to_user_tree;
guint32 offset = ext_offset;
guint32 msg_to_user_id;
int len_ent_id;
int len_tseq_num;
/* Get tlv len */
tlv_len = tvb_get_guint8(tvb, offset);
offset += 1;
/* Create a subtree */
cfdp_msg_to_user_tree = proto_tree_add_subtree(tree, tvb, offset-2, tlv_len+2,
ett_cfdp_filestore_resp, NULL, "Message To User TLV");
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_tlv_len, tvb, offset-1, 1, tlv_len);
msg_to_user_id = tvb_get_ntohl(tvb, offset);
/* Proxy operations */
if(msg_to_user_id == CFDP_MSG_TO_USER){
offset += 4;
tlv_type = tvb_get_guint8(tvb, offset);
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_proxy_msg_type, tvb, offset, 1, tlv_type);
offset += 1;
switch(tlv_type){
case PROXY_PUT_REQ:
tlv_len = tvb_get_guint8(tvb, offset);
offset += 1;
dissect_cfdp_dst_entity_id(tvb, pinfo, cfdp_msg_to_user_tree, offset, tlv_len);
offset += tlv_len;
tlv_len = tvb_get_guint8(tvb, offset);
offset += 1;
proto_tree_add_item(cfdp_msg_to_user_tree, hf_cfdp_src_file_name, tvb, offset, tlv_len, ENC_ASCII|ENC_NA);
offset += tlv_len;
tlv_len = tvb_get_guint8(tvb, offset);
offset += 1;
proto_tree_add_item(cfdp_msg_to_user_tree, hf_cfdp_dst_file_name, tvb, offset, tlv_len, ENC_ASCII|ENC_NA);
offset += tlv_len;
break;
case PROXY_MSG_TO_USER:
tlv_len = tvb_get_guint8(tvb, offset);
offset += 1;
proto_tree_add_item(cfdp_msg_to_user_tree, hf_cfdp_message_to_user, tvb, offset, tlv_len, ENC_NA);
break;
case PROXY_FILESTORE_REQ:
offset = dissect_cfdp_filestore_req_tlv(tvb, cfdp_msg_to_user_tree, offset);
break;
case PROXY_FAULT_HDL_OVERR:
aux_byte = tvb_get_guint8(tvb, offset);
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_condition_code, tvb, offset, 1, aux_byte);
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_handler_code, tvb, offset, 1, aux_byte);
offset += 1;
break;
case PROXY_TRANS_MODE:
aux_byte = tvb_get_guint8(tvb, offset);
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_spare_seven_2, tvb, offset, 1, aux_byte);
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_trans_mode_msg, tvb, offset, 1, aux_byte);
offset += 1;
break;
case PROXY_FLOW_LABEL:
proto_tree_add_item(cfdp_msg_to_user_tree, hf_cfdp_flow_label, tvb, offset, tlv_len, ENC_NA);
break;
case PROXY_SEGMENT_CONTROL:
aux_byte = tvb_get_guint8(tvb, offset);
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_spare_seven_2, tvb, offset, 1, aux_byte);
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_proxy_segment_control, tvb, offset, 1, aux_byte);
offset += 1;
break;
case PROXY_PUT_RESP:
aux_byte = tvb_get_guint8(tvb, offset);
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_condition_code, tvb, offset, 1, aux_byte);
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_spare_one, tvb, offset, 1, aux_byte);
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_condition_code, tvb, offset, 1, aux_byte);
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_proxy_delivery_code, tvb, offset, 1, aux_byte);
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_file_stat, tvb, offset, 1, aux_byte);
offset += 1;
break;
case PROXY_FILESTORE_RESP:
offset = dissect_cfdp_filestore_req_tlv(tvb, cfdp_msg_to_user_tree, offset);
break;
case PROXY_PUT_CANCEL:
break;
case ORIG_TRANS_ID:
aux_byte = tvb_get_guint8(tvb, offset);
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_res2, tvb, offset, 1, aux_byte);
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_entid_length, tvb, offset, 1, aux_byte);
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_res3, tvb, offset, 1, aux_byte);
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_transeqnum_length, tvb, offset, 1, aux_byte);
offset += 1;
len_ent_id = ((aux_byte & HDR_LEN_ENT_ID) >> 4) + 1;
dissect_cfdp_src_entity_id(tvb, pinfo, cfdp_msg_to_user_tree, offset, len_ent_id);
offset += len_ent_id;
len_tseq_num = (aux_byte & HDR_LEN_TSEQ_NUM) +1;
dissect_cfdp_tseq_num(tvb, pinfo, cfdp_msg_to_user_tree, offset, len_tseq_num);
offset += len_tseq_num;
break;
case DIRECTORY_LIST_REQ:
/* Directory Name */
tlv_len = tvb_get_guint8(tvb, offset);
offset += 1;
proto_tree_add_item(cfdp_msg_to_user_tree, hf_cfdp_directory_name, tvb, offset, tlv_len, ENC_ASCII|ENC_NA);
offset += tlv_len;
/* Directory File Name */
tlv_len = tvb_get_guint8(tvb, offset);
offset += 1;
proto_tree_add_item(cfdp_msg_to_user_tree, hf_cfdp_directory_file_name, tvb, offset, tlv_len, ENC_ASCII|ENC_NA);
offset += tlv_len;
break;
case DIRECTORY_LIST_RESP:
/* Listing Response Code */
aux_byte = tvb_get_guint8(tvb, offset);
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_listing_resp_code, tvb, offset, 1, aux_byte);
offset += 1;
/* Directory Name */
tlv_len = tvb_get_guint8(tvb, offset);
offset += 1;
proto_tree_add_item(cfdp_msg_to_user_tree, hf_cfdp_directory_name, tvb, offset, tlv_len, ENC_ASCII|ENC_NA);
offset += tlv_len;
/* Directory File Name */
tlv_len = tvb_get_guint8(tvb, offset);
offset += 1;
proto_tree_add_item(cfdp_msg_to_user_tree, hf_cfdp_directory_file_name, tvb, offset, tlv_len, ENC_ASCII|ENC_NA);
offset += tlv_len;
break;
case REMOTE_STAT_REP_REQ:
aux_byte = tvb_get_guint8(tvb, offset);
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_res2, tvb, offset, 1, aux_byte);
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_entid_length, tvb, offset, 1, aux_byte);
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_res3, tvb, offset, 1, aux_byte);
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_transeqnum_length, tvb, offset, 1, aux_byte);
offset += 1;
len_ent_id = ((aux_byte & HDR_LEN_ENT_ID) >> 4) + 1;
dissect_cfdp_src_entity_id(tvb, pinfo, cfdp_msg_to_user_tree, offset, len_ent_id);
offset += len_ent_id;
len_tseq_num = (aux_byte & HDR_LEN_TSEQ_NUM) +1;
dissect_cfdp_tseq_num(tvb, pinfo, cfdp_msg_to_user_tree, offset, len_tseq_num);
offset += len_tseq_num;
/* Report File Name */
tlv_len = tvb_get_guint8(tvb, offset);
offset += 1;
proto_tree_add_item(cfdp_msg_to_user_tree, hf_cfdp_report_file_name, tvb, offset, tlv_len, ENC_ASCII|ENC_NA);
offset += tlv_len;
break;
case REMOTE_STAT_REP_RESP:
aux_byte = tvb_get_guint8(tvb, offset);
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_trans_stat, tvb, offset, 1, aux_byte);
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_spare_five, tvb, offset, 1, aux_byte);
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_rep_resp_code, tvb, offset, 1, aux_byte);
offset += 1;
aux_byte = tvb_get_guint8(tvb, offset);
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_spare_one_2, tvb, offset, 1, aux_byte);
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_entid_length, tvb, offset, 1, aux_byte);
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_spare_one, tvb, offset, 1, aux_byte);
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_transeqnum_length, tvb, offset, 1, aux_byte);
offset += 1;
len_ent_id = ((aux_byte & HDR_LEN_ENT_ID) >> 4) + 1;
dissect_cfdp_src_entity_id(tvb, pinfo, cfdp_msg_to_user_tree, offset, len_ent_id);
offset += len_ent_id;
len_tseq_num = (aux_byte & HDR_LEN_TSEQ_NUM) +1;
dissect_cfdp_tseq_num(tvb, pinfo, cfdp_msg_to_user_tree, offset, len_tseq_num);
offset += len_tseq_num;
break;
case REMOTE_SUSPEND_REQ:
case REMOTE_RESUME_REQ:
aux_byte = tvb_get_guint8(tvb, offset);
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_spare_one_2, tvb, offset, 1, aux_byte);
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_entid_length, tvb, offset, 1, aux_byte);
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_spare_one, tvb, offset, 1, aux_byte);
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_transeqnum_length, tvb, offset, 1, aux_byte);
offset += 1;
len_ent_id = ((aux_byte & HDR_LEN_ENT_ID) >> 4) + 1;
dissect_cfdp_src_entity_id(tvb, pinfo, cfdp_msg_to_user_tree, offset, len_ent_id);
offset += len_ent_id;
len_tseq_num = (aux_byte & HDR_LEN_TSEQ_NUM) +1;
dissect_cfdp_tseq_num(tvb, pinfo, cfdp_msg_to_user_tree, offset, len_tseq_num);
offset += len_tseq_num;
break;
case REMOTE_SUSPEND_RESP:
case REMOTE_RESUME_RESP:
aux_byte = tvb_get_guint8(tvb, offset);
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_suspension_ind, tvb, offset, 1, aux_byte);
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_trans_stat_2, tvb, offset, 1, aux_byte);
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_spare_five, tvb, offset, 1, aux_byte);
offset += 1;
aux_byte = tvb_get_guint8(tvb, offset);
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_spare_one_2, tvb, offset, 1, aux_byte);
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_entid_length, tvb, offset, 1, aux_byte);
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_spare_one, tvb, offset, 1, aux_byte);
proto_tree_add_uint(cfdp_msg_to_user_tree, hf_cfdp_transeqnum_length, tvb, offset, 1, aux_byte);
offset += 1;
len_ent_id = ((aux_byte & HDR_LEN_ENT_ID) >> 4) + 1;
dissect_cfdp_src_entity_id(tvb, pinfo, cfdp_msg_to_user_tree, offset, len_ent_id);
offset += len_ent_id;
len_tseq_num = (aux_byte & HDR_LEN_TSEQ_NUM) +1;
dissect_cfdp_tseq_num(tvb, pinfo, cfdp_msg_to_user_tree, offset, len_tseq_num);
offset += len_tseq_num;
break;
default:
break;
}
}else{
proto_tree_add_item(cfdp_msg_to_user_tree, hf_cfdp_message_to_user, tvb, offset, tlv_len, ENC_NA);
offset += tlv_len;
}
return offset;
}
/* Dissect the Fault Handler Override TLV */
static guint32 dissect_cfdp_fault_handler_overr_tlv(tvbuff_t *tvb, proto_tree *tree, guint32 ext_offset){
guint8 aux_byte, tlv_len;
proto_tree *cfdp_fault_hdl_overr_tree;
guint32 offset = ext_offset;
/* Get tlv len */
tlv_len = tvb_get_guint8(tvb, offset);
offset += 1;
/* Create a subtree */
cfdp_fault_hdl_overr_tree = proto_tree_add_subtree(tree, tvb, offset-2, tlv_len+2,
ett_cfdp_fault_hdl_overr, NULL, "Fault Handler Override TLV");
proto_tree_add_uint(cfdp_fault_hdl_overr_tree, hf_cfdp_tlv_len, tvb, offset-1, 1, tlv_len);
aux_byte = tvb_get_guint8(tvb, offset);
proto_tree_add_uint(cfdp_fault_hdl_overr_tree, hf_cfdp_condition_code, tvb, offset, 1, aux_byte);
proto_tree_add_uint(cfdp_fault_hdl_overr_tree, hf_cfdp_handler_code, tvb, offset, 1, aux_byte);
offset += 1;
return offset;
}
/* Dissect the Flow Label TLV */
static guint32 dissect_cfdp_flow_label_tlv(tvbuff_t *tvb, proto_tree *tree, guint32 ext_offset){
guint8 tlv_len;
proto_tree *cfdp_flow_label_tree;
guint32 offset = ext_offset;
/* Get tlv len */
tlv_len = tvb_get_guint8(tvb, offset);
offset += 1;
/* Create a subtree */
cfdp_flow_label_tree = proto_tree_add_subtree(tree, tvb, offset-2, tlv_len+2,
ett_cfdp_flow_label, NULL, "Flow Label TLV");
/* It is undefined, so no specific encoding */
proto_tree_add_item(cfdp_flow_label_tree, hf_cfdp_flow_label, tvb, offset, tlv_len, ENC_NA);
return offset;
}
/* Dissect the End of File PDU */
static guint32 dissect_cfdp_eof_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 ext_offset, guint ext_packet_len){
guint8 aux_byte, tlv_type, tlv_len;
proto_tree *cfdp_fault_location_tree;
guint32 offset = ext_offset;
guint cfdp_packet_data_length = ext_packet_len;
aux_byte = tvb_get_guint8(tvb, offset);
proto_tree_add_uint(tree, hf_cfdp_condition_code, tvb, offset, 1, aux_byte);
proto_tree_add_uint(tree, hf_cfdp_spare_four, tvb, offset, 1, aux_byte);
offset += 1;
col_add_fstr(pinfo->cinfo, COL_INFO, "EOF (%s)", val_to_str_const((aux_byte & 0xF0) >> 4, cfdp_condition_codes, "Reserved Code"));
proto_tree_add_checksum(tree, tvb, offset, hf_cfdp_file_checksum, -1, NULL, pinfo, 0, ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS);
offset += 4;
proto_tree_add_item(tree, hf_cfdp_file_size, tvb, offset, 4, ENC_BIG_ENDIAN);
offset += 4;
if(offset < cfdp_packet_data_length){
tlv_type = tvb_get_guint8(tvb, offset);
offset += 1;
if(tlv_type == FAULT_LOCATION){
tlv_len = tvb_get_guint8(tvb, offset);
offset += 1;
cfdp_fault_location_tree = proto_tree_add_subtree(tree, tvb, offset-2, tlv_len+2,
ett_cfdp_fault_location, NULL, "Fault location TLV");
proto_tree_add_item(cfdp_fault_location_tree, hf_cfdp_entity, tvb, offset, tlv_len, ENC_NA);
offset += tlv_len;
}
}
return offset;
}
/* Dissect the Finished PDU */
static guint32 dissect_cfdp_finished_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 ext_offset, guint ext_packet_len){
guint32 offset = ext_offset;
guint8 aux_byte, tlv_type;
guint cfdp_packet_data_length = ext_packet_len;
aux_byte = tvb_get_guint8(tvb, offset);
proto_tree_add_uint(tree, hf_cfdp_condition_code, tvb, offset, 1, aux_byte);
proto_tree_add_uint(tree, hf_cfdp_end_system_stat, tvb, offset, 1, aux_byte);
proto_tree_add_uint(tree, hf_cfdp_delivery_code, tvb, offset, 1, aux_byte);
proto_tree_add_uint(tree, hf_cfdp_file_stat, tvb, offset, 1, aux_byte);
offset += 1;
col_add_fstr(pinfo->cinfo, COL_INFO, "Finished PDU (%s)", val_to_str_const((aux_byte & 0xF0) >> 4, cfdp_condition_codes, "Reserved Code"));
/* Add TLV fields */
while(offset < cfdp_packet_data_length){
tlv_type = tvb_get_guint8(tvb, offset);
offset += 1;
switch(tlv_type){
case FILESTORE_RESP:
offset = dissect_cfdp_filestore_resp_tlv(tvb, tree, offset);
break;
case FAULT_LOCATION:
offset = dissect_cfdp_fault_location_tlv(tvb, tree, offset);
break;
default:
break;
}
}
return offset;
}
/* Dissect the ACK PDU */
static guint32 dissect_cfdp_ack_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 ext_offset){
guint8 aux_byte;
guint32 offset = ext_offset;
aux_byte = tvb_get_guint8(tvb, offset);
proto_tree_add_uint(tree, hf_cfdp_dir_code_ack, tvb, offset, 1, aux_byte);
proto_tree_add_uint(tree, hf_cfdp_dir_subtype_ack, tvb, offset, 1, aux_byte);
offset += 1;
col_add_fstr(pinfo->cinfo, COL_INFO, "ACK PDU (%s)", val_to_str_const((aux_byte & 0xF0) >> 4, cfdp_directive_codes, "Unknown PDU"));
aux_byte = tvb_get_guint8(tvb, offset);
proto_tree_add_uint(tree, hf_cfdp_condition_code, tvb, offset, 1, aux_byte);
proto_tree_add_uint(tree, hf_cfdp_spare_two, tvb, offset, 1, aux_byte);
proto_tree_add_uint(tree, hf_cfdp_trans_stat_ack, tvb, offset, 1, aux_byte);
offset += 1;
return offset;
}
/* Dissect the Metadata PDU */
static guint32 dissect_cfdp_metadata_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 ext_offset, guint ext_packet_len){
guint8 aux_byte, tlv_type;
guint cfdp_packet_data_length = ext_packet_len;
guint32 offset = ext_offset;
aux_byte = tvb_get_guint8(tvb, offset);
proto_tree_add_uint(tree, hf_cfdp_segment_control, tvb, offset, 1, aux_byte);
proto_tree_add_uint(tree, hf_cfdp_spare_seven, tvb, offset, 1, aux_byte);
offset += 1;
proto_tree_add_item(tree, hf_cfdp_file_size, tvb, offset, 4, ENC_BIG_ENDIAN);
offset += 4;
aux_byte = tvb_get_guint8(tvb, offset);
if(aux_byte >0){
proto_tree_add_item(tree, hf_cfdp_src_file_name, tvb, offset+1, aux_byte, ENC_ASCII|ENC_NA);
offset += aux_byte+1;
aux_byte = tvb_get_guint8(tvb, offset);
proto_tree_add_item(tree, hf_cfdp_dst_file_name, tvb, offset+1, aux_byte, ENC_ASCII|ENC_NA);
offset += aux_byte+1;
}
/* Add TLV fields */
while(offset < cfdp_packet_data_length){
tlv_type = tvb_get_guint8(tvb, offset);
offset += 1;
switch(tlv_type){
case FILESTORE_REQ:
offset = dissect_cfdp_filestore_req_tlv(tvb, tree, offset);
break;
case MSG_TO_USER:
offset = dissect_cfdp_msg_to_user_tlv(tvb, pinfo, tree, offset);
break;
case FAULT_HDL_OVERR:
offset = dissect_cfdp_fault_handler_overr_tlv(tvb, tree, offset);
break;
case FLOW_LABEL:
offset = dissect_cfdp_flow_label_tlv(tvb, tree, offset);
break;
default:
break;
}
}
return offset;
}
/* Dissect the NAK PDU */
static guint32 dissect_cfdp_nak_pdu(tvbuff_t *tvb, proto_tree *tree, guint32 ext_offset, guint ext_packet_len){
guint32 offset = ext_offset;
guint cfdp_packet_data_length = ext_packet_len;
proto_tree_add_item(tree, hf_cfdp_nak_st_scope, tvb, offset, 4, ENC_BIG_ENDIAN);
offset += 4;
proto_tree_add_item(tree, hf_cfdp_nak_sp_scope, tvb, offset, 4, ENC_BIG_ENDIAN);
offset += 4;
proto_tree_add_item(tree, hf_cfdp_segment_requests, tvb, offset, cfdp_packet_data_length-9, ENC_NA);
offset += cfdp_packet_data_length-9;
return offset;
}
/* Dissect the Prompt PDU */
static guint32 dissect_cfdp_prompt_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 ext_offset){
guint8 aux_byte;
guint32 offset = ext_offset;
aux_byte = tvb_get_guint8(tvb, offset);
proto_tree_add_uint(tree, hf_cfdp_response_req, tvb, offset, 1, aux_byte);
proto_tree_add_uint(tree, hf_cfdp_spare_seven, tvb, offset, 1, aux_byte);
offset += 1;
col_add_fstr(pinfo->cinfo, COL_INFO, "Prompt PDU (%s)", val_to_str_const((aux_byte & 0x80) >> 7, cfdp_response_req, "Unknown"));
return offset;
}
/* Dissect the Keep Alive PDU */
static guint32 dissect_cfdp_keep_alive_pdu(tvbuff_t *tvb, proto_tree *tree, guint32 ext_offset){
guint32 offset = ext_offset;
proto_tree_add_item(tree, hf_cfdp_progress, tvb, offset, 4, ENC_BIG_ENDIAN);
offset += 4;
return offset;
}
/* Code to actually dissect the packets */
static int
dissect_cfdp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
{
int offset = 0;
proto_item *cfdp_packet;
proto_item *cfdp_tree;
proto_item *cfdp_header;
proto_tree *cfdp_header_tree;
gint cfdp_packet_length;
gint cfdp_packet_reported_length;
gint cfdp_packet_header_length;
gint cfdp_packet_data_length;
gint length;
guint8 first_byte;
guint8 second_byte;
gint len_ent_id;
gint len_tseq_num;
col_set_str(pinfo->cinfo, COL_PROTOCOL, "CFDP");
col_clear(pinfo->cinfo, COL_INFO);
cfdp_packet_reported_length = tvb_reported_length_remaining(tvb, 0);
cfdp_packet_header_length = (tvb_get_guint8(tvb, 3) & HDR_LEN_TSEQ_NUM) + 1 + 2*(((tvb_get_guint8(tvb, 3) & HDR_LEN_ENT_ID) >>4) +1) + CFDP_HEADER_FIXED_FIELDS_LEN;
cfdp_packet_length = tvb_get_ntohs(tvb, 1) + cfdp_packet_header_length;
/* Min length is size of header plus 2 octets, whereas max length is reported length.
* If the length field in the CFDP header is outside of these bounds,
* use the value it violates. Otherwise, use the length field value.
*/
if(cfdp_packet_length > cfdp_packet_reported_length)
length = cfdp_packet_reported_length;
else if(cfdp_packet_length < cfdp_packet_header_length + 2)
length = cfdp_packet_header_length + 2;
else
length = cfdp_packet_length;
/* Build the cfdp tree */
cfdp_packet = proto_tree_add_item(tree, proto_cfdp, tvb, 0, length, ENC_NA);
cfdp_tree = proto_item_add_subtree(cfdp_packet, ett_cfdp);
cfdp_header_tree = proto_tree_add_subtree(cfdp_tree, tvb, offset, cfdp_packet_header_length,
ett_cfdp_header, &cfdp_header, "CFDP Header");
first_byte = tvb_get_guint8(tvb, offset);
/* CRC code is not included in the packet data length */
cfdp_packet_data_length = tvb_get_ntohs(tvb, 1)-2*((first_byte & HDR_CRCF) >>1);
proto_tree_add_uint(cfdp_header_tree, hf_cfdp_version, tvb, offset, 1, first_byte);
proto_tree_add_uint(cfdp_header_tree, hf_cfdp_pdu_type, tvb, offset, 1, first_byte);
proto_tree_add_uint(cfdp_header_tree, hf_cfdp_direction, tvb, offset, 1, first_byte);
proto_tree_add_uint(cfdp_header_tree, hf_cfdp_trans_mode, tvb, offset, 1, first_byte);
proto_tree_add_uint(cfdp_header_tree, hf_cfdp_crc_flag, tvb, offset, 1, first_byte);
proto_tree_add_uint(cfdp_header_tree, hf_cfdp_res1, tvb, offset, 1, first_byte);
offset += 1;
proto_tree_add_item(cfdp_header_tree, hf_cfdp_data_length, tvb, offset, 2, ENC_BIG_ENDIAN);
offset += 2;
second_byte = tvb_get_guint8(tvb, offset);
proto_tree_add_uint(cfdp_header_tree, hf_cfdp_res2, tvb, offset, 1, second_byte);
proto_tree_add_uint(cfdp_header_tree, hf_cfdp_entid_length, tvb, offset, 1, second_byte);
proto_tree_add_uint(cfdp_header_tree, hf_cfdp_res3, tvb, offset, 1, second_byte);
proto_tree_add_uint(cfdp_header_tree, hf_cfdp_transeqnum_length, tvb, offset, 1, second_byte);
offset += 1;
len_ent_id = ((second_byte & HDR_LEN_ENT_ID) >> 4) + 1;
dissect_cfdp_src_entity_id(tvb, pinfo, cfdp_header_tree, offset, len_ent_id);
offset += len_ent_id;
len_tseq_num = (second_byte & HDR_LEN_TSEQ_NUM) +1;
dissect_cfdp_tseq_num(tvb, pinfo, cfdp_header_tree, offset, len_tseq_num);
offset += len_tseq_num;
dissect_cfdp_dst_entity_id(tvb, pinfo, cfdp_header_tree, offset, len_ent_id);
offset += len_ent_id;
proto_item_set_end(cfdp_header, tvb, offset);
/* Build the File Directive or the File Data tree */
if(!(first_byte & HDR_TYPE_CFDP))
{
proto_item *cfdp_file_directive_header;
proto_tree *cfdp_file_directive_header_tree;
guint8 directive_code;
cfdp_file_directive_header_tree = proto_tree_add_subtree(cfdp_tree, tvb, offset, cfdp_packet_data_length,
ett_cfdp_file_directive_header, &cfdp_file_directive_header, "CFDP File Directive");
directive_code = tvb_get_guint8(tvb, offset);
proto_tree_add_uint(cfdp_file_directive_header_tree, hf_cfdp_file_directive_type, tvb, offset, 1, directive_code);
offset += 1;
col_add_fstr(pinfo->cinfo, COL_INFO, "%s PDU", val_to_str(directive_code, cfdp_directive_codes, "Reserved (%d)"));
switch(directive_code)
{
case EOF_PDU:
offset = dissect_cfdp_eof_pdu(tvb, pinfo, cfdp_file_directive_header_tree, offset, cfdp_packet_data_length);
break;
case FINISHED_PDU:
offset = dissect_cfdp_finished_pdu(tvb, pinfo, cfdp_file_directive_header_tree, offset, cfdp_packet_data_length);
break;
case ACK_PDU:
offset = dissect_cfdp_ack_pdu(tvb, pinfo, cfdp_file_directive_header_tree, offset);
break;
case METADATA_PDU:
offset = dissect_cfdp_metadata_pdu(tvb, pinfo, cfdp_file_directive_header_tree, offset, cfdp_packet_data_length);
break;
case NAK_PDU:
offset = dissect_cfdp_nak_pdu(tvb, cfdp_file_directive_header_tree, offset, cfdp_packet_data_length);
break;
case PROMPT_PDU:
offset = dissect_cfdp_prompt_pdu(tvb, pinfo, cfdp_file_directive_header_tree, offset);
break;
case KEEP_ALIVE_PDU:
offset = dissect_cfdp_keep_alive_pdu(tvb, cfdp_file_directive_header_tree, offset);
break;
default:
break;
}
proto_item_set_end(cfdp_file_directive_header, tvb, offset);
}else{
proto_tree *cfdp_file_data_header_tree;
col_add_fstr(pinfo->cinfo, COL_INFO, "File Data PDU");
cfdp_file_data_header_tree = proto_tree_add_subtree(cfdp_tree, tvb, offset, cfdp_packet_data_length,
ett_cfdp_file_data_header, NULL, "CFDP File Data");
proto_tree_add_item(cfdp_file_data_header_tree, hf_cfdp_file_data_offset, tvb, offset, 4, ENC_BIG_ENDIAN);
offset += 4;
proto_tree_add_item(cfdp_file_data_header_tree, hf_cfdp_user_data, tvb, offset, cfdp_packet_data_length-4, ENC_NA);
offset += cfdp_packet_data_length-4;
}
if(first_byte & HDR_CRCF){
proto_item *cfdp_crc;
proto_tree *cfdp_crc_tree;
cfdp_crc_tree = proto_tree_add_subtree(cfdp_tree, tvb, offset, 2, ett_cfdp_crc, &cfdp_crc, "CRC");
proto_tree_add_item(cfdp_crc_tree, hf_cfdp_crc, tvb, offset, 2, ENC_BIG_ENDIAN);
offset += 2;
proto_item_set_end(cfdp_crc, tvb, offset);
}
/* Give the data dissector any bytes past the CFDP packet length */
call_data_dissector(tvb_new_subset_remaining(tvb, offset), pinfo, tree);
return tvb_captured_length(tvb);
}
void
proto_register_cfdp(void)
{
static hf_register_info hf[] = {
{ &hf_cfdp_version,
{ "Version", "cfdp.version",
FT_UINT8, BASE_DEC, NULL, HDR_VERSION_CFDP,
NULL, HFILL }
},
{ &hf_cfdp_pdu_type,
{ "PDU Type", "cfdp.pdu_type",
FT_UINT8, BASE_DEC, VALS(cfdp_pdu_type), HDR_TYPE_CFDP,
NULL, HFILL }
},
{ &hf_cfdp_direction,
{ "Direction", "cfdp.direction",
FT_UINT8, BASE_DEC, VALS(cfdp_direction), HDR_DIR,
NULL, HFILL }
},
{ &hf_cfdp_trans_mode,
{ "Trans. Mode", "cfdp.trans_mode",
FT_UINT8, BASE_DEC, VALS(cfdp_trans_mode), HDR_TMODE,
NULL, HFILL }
},
{ &hf_cfdp_crc_flag,
{ "CRC Flag", "cfdp.crc_flag",
FT_UINT8, BASE_DEC, VALS(cfdp_crc_flag), HDR_CRCF,
NULL, HFILL }
},
{ &hf_cfdp_res1,
{ "Bit reserved 1", "cfdp.res1",
FT_UINT8, BASE_DEC, NULL, HDR_RES1,
NULL, HFILL }
},
{ &hf_cfdp_data_length,
{ "PDU Data length", "cfdp.data_length",
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_cfdp_res2,
{ "Bit reserved 2", "cfdp.res2",
FT_UINT8, BASE_DEC, NULL, 0x80,
NULL, HFILL }
},
{ &hf_cfdp_entid_length,
{ "Length of entity IDs", "cfdp.entid_length",
FT_UINT8, BASE_DEC, NULL, 0x70,
NULL, HFILL }
},
{ &hf_cfdp_res3,
{ "Bit reserved 3", "cfdp.res3",
FT_UINT8, BASE_DEC, NULL, 0x08,
NULL, HFILL }
},
{ &hf_cfdp_transeqnum_length,
{ "Length of Transaction sequence number", "cfdp.transeqnum_length",
FT_UINT8, BASE_DEC, NULL, 0x07,
NULL, HFILL }
},
{ &hf_cfdp_srcid,
{ "Source entity ID", "cfdp.srcid",
FT_UINT64, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_cfdp_transeqnum,
{ "Transaction sequence number", "cfdp.transeqnum",
FT_UINT64, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_cfdp_dstid,
{ "Destination entity ID", "cfdp.dstid",
FT_UINT64, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_cfdp_file_directive_type,
{ "File Directive type", "cfdp.fdtype",
FT_UINT8, BASE_DEC, VALS(cfdp_file_directive_type), 0x0,
NULL, HFILL }
},
{ &hf_cfdp_file_data_offset,
{ "Offset", "cfdp.offset",
FT_UINT32, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_cfdp_progress,
{ "Progress", "cfdp.progress",
FT_UINT32, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_cfdp_dir_code_ack,
{ "PDU acknowledged", "cfdp.dir_code_ack",
FT_UINT8, BASE_DEC, VALS(cfdp_file_directive_type), 0xf0,
NULL, HFILL }
},
{ &hf_cfdp_dir_subtype_ack,
{ "Directive subtype code", "cfdp.dir_subtype_ack",
FT_UINT8, BASE_DEC, NULL, 0x0f,
NULL, HFILL }
},
{ &hf_cfdp_condition_code,
{ "Condition Code", "cfdp.condition_code",
FT_UINT8, BASE_DEC, VALS(cfdp_condition_codes), 0xf0,
NULL, HFILL }
},
{ &hf_cfdp_spare_one,
{ "Spare", "cfdp.spare_one",
FT_UINT8, BASE_DEC, NULL, 0x08,
NULL, HFILL }
},
{ &hf_cfdp_spare_one_2,
{ "Spare", "cfdp.spare_one_2",
FT_UINT8, BASE_DEC, NULL, 0x80,
NULL, HFILL }
},
{ &hf_cfdp_spare_two,
{ "Spare", "cfdp.spare_two",
FT_UINT8, BASE_DEC, NULL, 0x0c,
NULL, HFILL }
},
{ &hf_cfdp_spare_four,
{ "Spare", "cfdp.spare_four",
FT_UINT8, BASE_DEC, NULL, 0x0f,
NULL, HFILL }
},
{ &hf_cfdp_spare_five,
{ "Spare", "cfdp.spare_five",
FT_UINT8, BASE_DEC, NULL, 0x3E,
NULL, HFILL }
},
{ &hf_cfdp_spare_seven,
{ "Spare", "cfdp.spare_seven",
FT_UINT8, BASE_DEC, NULL, 0x7f,
NULL, HFILL }
},
{ &hf_cfdp_spare_seven_2,
{ "Spare", "cfdp.spare_seven_2",
FT_UINT8, BASE_DEC, NULL, 0xfe,
NULL, HFILL }
},
{ &hf_cfdp_trans_stat_ack,
{ "Transaction status", "cfdp.trans_stat_ack",
FT_UINT8, BASE_DEC, VALS(cfdp_trans_stat_ack), 0x03,
NULL, HFILL }
},
{ &hf_cfdp_trans_stat,
{ "Transaction status", "cfdp.trans_stat",
FT_UINT8, BASE_DEC, VALS(cfdp_trans_stat_ack), 0xC0,
NULL, HFILL }
},
{ &hf_cfdp_trans_stat_2,
{ "Transaction status", "cfdp.trans_stat_2",
FT_UINT8, BASE_DEC, VALS(cfdp_trans_stat_ack), 0x60,
NULL, HFILL }
},
{ &hf_cfdp_file_checksum,
{ "Checksum", "cfdp.checksum",
FT_UINT32, BASE_HEX, NULL, 0x0,
NULL, HFILL }
},
{ &hf_cfdp_file_size,
{ "File size", "cfdp.file_size",
FT_UINT32, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_cfdp_end_system_stat,
{ "End system status", "cfdp.end_system_stat",
FT_UINT8, BASE_DEC, VALS(cfdp_end_system_stat), 0x08,
NULL, HFILL }
},
{ &hf_cfdp_delivery_code,
{ "Delivery code", "cfdp.delivery_code",
FT_UINT8, BASE_DEC, VALS(cfdp_delivery_code), 0x04,
NULL, HFILL }
},
{ &hf_cfdp_file_stat,
{ "File status", "cfdp.file_status",
FT_UINT8, BASE_DEC, VALS(cfdp_file_stat), 0x03,
NULL, HFILL }
},
{ &hf_cfdp_segment_control,
{ "Segmentation control", "cfdp.segment_control",
FT_UINT8, BASE_DEC, VALS(cfdp_segment_control), 0x80,
NULL, HFILL }
},
{ &hf_cfdp_tlv_len,
{ "Length", "cfdp.tlv_length",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_cfdp_src_file_name,
{"Source file name", "cfdp.src_file_name", FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL}
},
{ &hf_cfdp_dst_file_name,
{"Destination file name", "cfdp.dst_file_name", FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL}
},
{ &hf_cfdp_first_file_name,
{"First file name", "cfdp.first_file_name", FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL}
},
{ &hf_cfdp_second_file_name,
{"Second file name", "cfdp.second_file_name", FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL}
},
{ &hf_cfdp_nak_st_scope,
{"Start of scope", "cfdp.nak_st_scope", FT_UINT32, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{ &hf_cfdp_nak_sp_scope,
{"End of scope", "cfdp.nak_sp_scope", FT_UINT32, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{ &hf_cfdp_crc,
{"CRC", "cfdp.crc", FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL}
},
{ &hf_cfdp_action_code,
{"Action code", "cfdp.action_code", FT_UINT8, BASE_DEC, VALS(cfdp_action_code), 0xF0,
NULL, HFILL}
},
{ &hf_cfdp_status_code_1,
{"Status code", "cfdp.status_code_1", FT_UINT8, BASE_DEC, VALS(cfdp_status_code_1), 0x0F,
NULL, HFILL}
},
{ &hf_cfdp_status_code_2,
{"Status code", "cfdp.status_code_2", FT_UINT8, BASE_DEC, VALS(cfdp_status_code_2), 0x0F,
NULL, HFILL}
},
{ &hf_cfdp_status_code_3,
{"Status code", "cfdp.status_code_3", FT_UINT8, BASE_DEC, VALS(cfdp_status_code_3), 0x0F,
NULL, HFILL}
},
{ &hf_cfdp_status_code_4,
{"Status code", "cfdp.status_code_4", FT_UINT8, BASE_DEC, VALS(cfdp_status_code_4), 0x0F,
NULL, HFILL}
},
{ &hf_cfdp_status_code_5,
{"Status code", "cfdp.status_code_5", FT_UINT8, BASE_DEC, VALS(cfdp_status_code_5), 0x0F,
NULL, HFILL}
},
{ &hf_cfdp_status_code_6,
{"Status code", "cfdp.status_code_6", FT_UINT8, BASE_DEC, VALS(cfdp_status_code_6), 0x0F,
NULL, HFILL}
},
{ &hf_cfdp_status_code_7,
{"Status code", "cfdp.status_code_7", FT_UINT8, BASE_DEC, VALS(cfdp_status_code_7), 0x0F,
NULL, HFILL}
},
{ &hf_cfdp_status_code_8,
{"Status code", "cfdp.status_code_8", FT_UINT8, BASE_DEC, VALS(cfdp_status_code_8), 0x0F,
NULL, HFILL}
},
{ &hf_cfdp_handler_code,
{ "Handler Code", "cfdp.handler_code",
FT_UINT8, BASE_DEC, VALS(cfdp_handler_codes), 0x0F,
NULL, HFILL }
},
{ &hf_cfdp_trans_mode_msg,
{ "Trans. Mode", "cfdp.trans_mode_msg",
FT_UINT8, BASE_DEC, VALS(cfdp_trans_mode), 0x01,
NULL, HFILL }
},
{ &hf_cfdp_proxy_msg_type,
{ "Proxy Message Type", "cfdp.proxy_msg_type",
FT_UINT8, BASE_DEC | BASE_EXT_STRING, &cfdp_proxy_msg_type_ext, 0x0,
NULL, HFILL }
},
{ &hf_cfdp_proxy_segment_control,
{ "Segmentation control", "cfdp.proxy_segment_control",
FT_UINT8, BASE_DEC, VALS(cfdp_segment_control), 0x01,
NULL, HFILL }
},
{ &hf_cfdp_proxy_delivery_code,
{ "Delivery code", "cfdp.proxy_delivery_code",
FT_UINT8, BASE_DEC, VALS(cfdp_delivery_code), 0x04,
NULL, HFILL }
},
{ &hf_cfdp_response_req,
{ "Response required", "cfdp.response_req",
FT_UINT8, BASE_DEC, VALS(cfdp_response_req), 0x80,
NULL, HFILL }
},
{ &hf_cfdp_directory_name,
{"Directory Name", "cfdp.directory_name", FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL}
},
{ &hf_cfdp_directory_file_name,
{"Directory File Name", "cfdp.directory_file_name", FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL}
},
{ &hf_cfdp_listing_resp_code,
{"Listing Response Code", "cfdp.listing_resp_code",
FT_UINT8, BASE_DEC, VALS(cfdp_listing_resp_code), 0x80,
NULL, HFILL}
},
{ &hf_cfdp_report_file_name,
{"Report File Name", "cfdp.report_file_name", FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL}
},
{ &hf_cfdp_rep_resp_code,
{"Report Response Code", "cfdp.rep_resp_code",
FT_UINT8, BASE_DEC, VALS(cfdp_rep_resp_code), 0x01,
NULL, HFILL}
},
{ &hf_cfdp_suspension_ind,
{"Suspension indicator", "cfdp.suspension_ind",
FT_UINT8, BASE_DEC, VALS(cfdp_suspension_ind), 0x80,
NULL, HFILL}
},
/* Generated from convert_proto_tree_add_text.pl */
{ &hf_cfdp_filestore_message, { "Filestore Message", "cfdp.filestore_message", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_cfdp_entity, { "Entity", "cfdp.entity", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_cfdp_message_to_user, { "Message to User", "cfdp.message_to_user", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_cfdp_flow_label, { "Flow label", "cfdp.flow_label", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_cfdp_segment_requests, { "Segment requests", "cfdp.segment_requests", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_cfdp_user_data, { "User Data", "cfdp.user_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
};
/* Setup protocol subtree array */
static gint *ett[] = {
&ett_cfdp,
&ett_cfdp_header,
&ett_cfdp_file_directive_header,
&ett_cfdp_file_data_header,
&ett_cfdp_fault_location,
&ett_cfdp_crc,
&ett_cfdp_filestore_req,
&ett_cfdp_filestore_resp,
&ett_cfdp_msg_to_user,
&ett_cfdp_fault_hdl_overr,
&ett_cfdp_flow_label
};
static ei_register_info ei[] = {
{ &ei_cfdp_bad_length, { "cfdp.bad_length", PI_MALFORMED, PI_ERROR, "Bad length field", EXPFILL }},
};
expert_module_t* expert_cfdp;
/* Register the protocol name and description */
proto_cfdp = proto_register_protocol("CFDP", "CFDP", "cfdp");
/* Required function calls to register the header fields and subtrees used */
proto_register_field_array(proto_cfdp, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
expert_cfdp = expert_register_protocol(proto_cfdp);
expert_register_field_array(expert_cfdp, ei, array_length(ei));
cfdp_handle = register_dissector("cfdp", dissect_cfdp, proto_cfdp);
}
void
proto_reg_handoff_cfdp(void)
{
dissector_add_uint("ccsds.apid", CFDP_APID, cfdp_handle);
dissector_add_for_decode_as_with_preference("udp.port", cfdp_handle);
}
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* vi: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/