CIP: Improve string handling

1. Add support for STRINGI
2. Add File Name attribute that is a STRINGI
3. CCO Get/Set Attr All: Connection Name is STRING2 not ASCII
4. TCP/IP Host Name attribute is not just a STRING. It also needs a pad byte.
5. Minor: Fix byte highlighting for CCO I/O Mapping tree
6. Minor: All back byte highlighting for Get Attr All Rsp individual attributes

Change-Id: Ib10d6f2e86e39e8cd6335dc6b6dbebbd1c4d8e64
Reviewed-on: https://code.wireshark.org/review/18166
Petri-Dish: Michael Mann <mmann78@netscape.net>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Michael Mann <mmann78@netscape.net>
This commit is contained in:
D. Ulis 2016-10-12 09:36:24 -04:00 committed by Michael Mann
parent 464e6cdc99
commit 4d8581d7e1
3 changed files with 136 additions and 54 deletions

View File

@ -405,6 +405,12 @@ static int hf_conn_mgr_conn_open_bits = -1;
static int hf_conn_mgr_cpu_utilization = -1;
static int hf_conn_mgr_max_buff_size = -1;
static int hf_conn_mgr_buff_size_remaining = -1;
static int hf_stringi_number_char = -1;
static int hf_stringi_language_char = -1;
static int hf_stringi_char_string_struct = -1;
static int hf_stringi_char_set = -1;
static int hf_stringi_international_string = -1;
static int hf_file_filename = -1;
static int hf_time_sync_ptp_enable = -1;
static int hf_time_sync_is_synchronized = -1;
static int hf_time_sync_sys_time_micro = -1;
@ -3443,6 +3449,8 @@ static attribute_info_t cip_attribute_vals[] = {
{0x06, FALSE, 12, 10, "Max Buff Size", cip_udint, &hf_conn_mgr_max_buff_size, NULL },
{0x06, FALSE, 13, 11, "Buff Size Remaining", cip_udint, &hf_conn_mgr_buff_size_remaining, NULL },
/* File Object (instance attributes) */
{0x37, FALSE, 4, -1, "File Name", cip_stringi, &hf_file_filename, NULL },
/* Time Sync Object (class attributes) */
{0x43, TRUE, 1, 0, CLASS_ATTRIBUTE_1_NAME, cip_uint, &hf_attr_class_revision, NULL },
@ -4903,8 +4911,87 @@ void dissect_cip_date_and_time(proto_tree *tree, tvbuff_t *tvb, int offset, int
proto_tree_add_time(tree, hf_datetime, tvb, offset, 6, &computed_time);
}
static int
dissect_cip_attribute(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb,
int dissect_cip_string_type(packet_info *pinfo, proto_tree *tree, proto_item *item,
tvbuff_t *tvb, int offset, int hf_type, int string_type)
{
guint32 string_size_field_len;
guint32 string_size;
guint string_encoding;
int parsed_len;
int total_len;
total_len = tvb_reported_length_remaining(tvb, offset);
switch (string_type)
{
case CIP_SHORT_STRING_TYPE:
string_size = tvb_get_guint8(tvb, offset);
string_encoding = ENC_ASCII | ENC_NA;
string_size_field_len = 1;
break;
case CIP_STRING_TYPE:
string_size = tvb_get_letohs(tvb, offset);
string_encoding = ENC_ASCII | ENC_NA;
string_size_field_len = 2;
break;
case CIP_STRING2_TYPE:
string_size = tvb_get_letohs(tvb, offset) * 2;
string_encoding = ENC_UCS_2 | ENC_LITTLE_ENDIAN;
string_size_field_len = 2;
break;
default:
// Unsupported.
return total_len;
break;
}
if (total_len < (int)(string_size + string_size_field_len))
{
expert_add_info(pinfo, item, &ei_mal_missing_string_data);
parsed_len = total_len;
}
else
{
proto_tree_add_item(tree, hf_type, tvb, offset + string_size_field_len, string_size, string_encoding);
parsed_len = string_size + string_size_field_len;
}
return parsed_len;
}
static int dissect_cip_stringi(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb, int offset)
{
int parsed_len = 1;
guint32 num_char = 0;
proto_tree_add_item_ret_uint(tree, hf_stringi_number_char, tvb, offset, 1, ENC_LITTLE_ENDIAN, &num_char);
for (guint32 i = 0; i < num_char; ++i)
{
proto_tree_add_item(tree, hf_stringi_language_char, tvb, offset + 1, 3, ENC_ASCII | ENC_NA);
guint32 char_string_type = 0;
proto_tree_add_item_ret_uint(tree, hf_stringi_char_string_struct, tvb, offset + 4, 1, ENC_LITTLE_ENDIAN, &char_string_type);
proto_tree_add_item(tree, hf_stringi_char_set, tvb, offset + 5, 2, ENC_LITTLE_ENDIAN);
parsed_len += 6;
if (char_string_type != CIP_STRING_TYPE
&& char_string_type != CIP_SHORT_STRING_TYPE
&& char_string_type != CIP_STRING2_TYPE)
{
// Unsupported type.
break;
}
parsed_len += dissect_cip_string_type(pinfo, tree, item, tvb, offset + parsed_len, hf_stringi_international_string, char_string_type);
}
return parsed_len;
}
int dissect_cip_attribute(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb,
attribute_info_t* attr, int offset, int total_len)
{
int i, temp_data, temp_time, hour, min, sec, ms,
@ -4969,31 +5056,10 @@ dissect_cip_attribute(packet_info *pinfo, proto_tree *tree, proto_item *item, tv
consumed = 8;
break;
case cip_short_string:
temp_data = tvb_get_guint8( tvb, offset );
if (total_len < temp_data + 1)
{
expert_add_info(pinfo, item, &ei_mal_missing_string_data);
consumed = total_len;
}
else
{
proto_tree_add_item(tree, *(attr->phf), tvb, offset+1, temp_data, ENC_ASCII|ENC_NA);
consumed = 1+temp_data;
}
consumed = dissect_cip_string_type(pinfo, tree, item, tvb, offset, *(attr->phf), CIP_SHORT_STRING_TYPE);
break;
case cip_string:
temp_data = tvb_get_letohs( tvb, offset );
if (total_len < temp_data + 2)
{
expert_add_info(pinfo, item, &ei_mal_missing_string_data);
consumed = total_len;
}
else
{
proto_tree_add_item(tree, *(attr->phf), tvb, offset+2, temp_data, ENC_ASCII|ENC_NA);
consumed = 2+temp_data;
}
consumed = dissect_cip_string_type(pinfo, tree, item, tvb, offset, *(attr->phf), CIP_STRING_TYPE);
break;
case cip_dissector_func:
consumed = attr->pdissect(pinfo, tree, item, tvb, offset, total_len);
@ -5023,22 +5089,12 @@ dissect_cip_attribute(packet_info *pinfo, proto_tree *tree, proto_item *item, tv
consumed = 4;
break;
case cip_string2:
temp_data = tvb_get_letohs(tvb, offset) * 2;
if (total_len < temp_data + 2)
{
expert_add_info(pinfo, item, &ei_mal_missing_string_data);
consumed = total_len;
}
else
{
const char* string_text = tvb_get_string_enc(wmem_packet_scope(), tvb, offset + 2, temp_data, ENC_UCS_2 | ENC_LITTLE_ENDIAN);
proto_tree_add_string(tree, *(attr->phf), tvb, offset, temp_data + 2, string_text);
consumed = 2 + temp_data;
}
consumed = dissect_cip_string_type(pinfo, tree, item, tvb, offset, *(attr->phf), CIP_STRING2_TYPE);
break;
case cip_stringi:
consumed = dissect_cip_stringi(pinfo, tree, item, tvb, offset);
break;
case cip_stringN:
case cip_stringi:
/* CURRENTLY NOT SUPPORTED */
expert_add_info(pinfo, item, &ei_proto_unsupported_datatype);
consumed = total_len;
@ -5563,6 +5619,8 @@ void dissect_cip_get_attribute_all_rsp(tvbuff_t *tvb, packet_info *pinfo, proto_
att_tree = proto_item_add_subtree(att_item, ett_cip_get_attributes_all_item);
att_size = dissect_cip_attribute(pinfo, att_tree, att_item, tvb, attr, offset, len_remain);
proto_item_set_len(att_item, att_size);
offset += att_size;
}
@ -6772,15 +6830,15 @@ dissect_cip_class_mb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *
*
************************************************/
static int
dissect_cip_cco_all_attribute_common( proto_tree *cmd_tree, tvbuff_t *tvb, int offset, int item_length, packet_info *pinfo)
dissect_cip_cco_all_attribute_common( proto_tree *cmd_tree, proto_item *ti,
tvbuff_t *tvb, int offset, int item_length, packet_info *pinfo)
{
proto_item *pi, *confgi;
proto_tree *tdi_tree, *iomap_tree, *epath_tree;
proto_tree *ncp_tree, *confg_tree;
int conn_path_size, variable_data_size = 0, config_data_size;
int connection_name_size, iomap_size, ot_rtf, to_rtf;
int iomap_size, ot_rtf, to_rtf;
int temp_data;
char* str_connection_name;
/* Connection flags */
temp_data = tvb_get_letohs( tvb, offset);
@ -6859,16 +6917,12 @@ dissect_cip_cco_all_attribute_common( proto_tree *cmd_tree, tvbuff_t *tvb, int o
variable_data_size += (config_data_size+2);
/* Connection Name */
connection_name_size = tvb_get_guint8( tvb, offset+variable_data_size);
str_connection_name = tvb_get_string_enc(wmem_packet_scope(), tvb, offset+variable_data_size+2, connection_name_size, ENC_ASCII);
proto_tree_add_string(cmd_tree, hf_cip_cco_connection_name, tvb, offset+variable_data_size, connection_name_size+2, str_connection_name);
variable_data_size += ((connection_name_size*2)+2);
variable_data_size += dissect_cip_string_type(pinfo, cmd_tree, ti, tvb, offset + variable_data_size, hf_cip_cco_connection_name, CIP_STRING2_TYPE);
/* I/O Mapping */
iomap_size = tvb_get_letohs( tvb, offset+variable_data_size+2);
iomap_tree = proto_tree_add_subtree( cmd_tree, tvb, offset+variable_data_size, iomap_size+2, ett_cco_iomap, NULL, "I/O Mapping");
iomap_tree = proto_tree_add_subtree( cmd_tree, tvb, offset+variable_data_size, iomap_size+4, ett_cco_iomap, NULL, "I/O Mapping");
proto_tree_add_item(iomap_tree, hf_cip_cco_iomap_format_number, tvb, offset+variable_data_size, 2, ENC_LITTLE_ENDIAN );
proto_tree_add_uint_format_value(iomap_tree, hf_cip_cco_iomap_size, tvb, offset+variable_data_size+2, 2, iomap_size, "%d (bytes)", iomap_size);
@ -6941,7 +6995,7 @@ dissect_cip_cco_all_attribute_common( proto_tree *cmd_tree, tvbuff_t *tvb, int o
}
static void
dissect_cip_cco_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, int item_length, packet_info *pinfo )
dissect_cip_cco_data( proto_tree *item_tree, proto_item *ti, tvbuff_t *tvb, int offset, int item_length, packet_info *pinfo )
{
proto_item *rrsc_item;
proto_tree *rrsc_tree, *cmd_data_tree, *con_st_tree;
@ -7020,7 +7074,7 @@ dissect_cip_cco_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, int item
/* Extended Status */
proto_tree_add_item(con_st_tree, hf_cip_cco_ext_status, tvb, offset+4+add_stat_size+2, 2, ENC_LITTLE_ENDIAN);
dissect_cip_cco_all_attribute_common( cmd_data_tree, tvb, offset+4+add_stat_size+4, item_length, pinfo);
dissect_cip_cco_all_attribute_common(cmd_data_tree, ti, tvb, offset+4+add_stat_size+4, item_length, pinfo);
}
}
else
@ -7072,7 +7126,7 @@ dissect_cip_cco_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, int item
}
/* Set Attribute All (instance) request */
dissect_cip_cco_all_attribute_common(cmd_data_tree, tvb, offset+2+req_path_size, item_length, pinfo);
dissect_cip_cco_all_attribute_common(cmd_data_tree, ti, tvb, offset+2+req_path_size, item_length, pinfo);
break;
default:
@ -7097,7 +7151,7 @@ dissect_cip_class_cco(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void
ti = proto_tree_add_item(tree, proto_cip_class_cco, tvb, 0, -1, ENC_NA);
class_tree = proto_item_add_subtree( ti, ett_cip_class_cco );
dissect_cip_cco_data( class_tree, tvb, 0, tvb_reported_length(tvb), pinfo );
dissect_cip_cco_data( class_tree, ti, tvb, 0, tvb_reported_length(tvb), pinfo );
return tvb_reported_length(tvb);
}
@ -7644,6 +7698,13 @@ proto_register_cip(void)
{ &hf_conn_mgr_max_buff_size, { "Max Buff Size", "cip.cm.max_buff_size", FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
{ &hf_conn_mgr_buff_size_remaining, { "Buff Size Remaining", "cip.cm.buff_remain", FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
{ &hf_stringi_number_char, { "Number of Characters", "cip.stringi.num", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } },
{ &hf_stringi_language_char, { "Language Chars", "cip.stringi.language_char", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } },
{ &hf_stringi_char_string_struct, { "Char String Struct", "cip.stringi.char_string_struct", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } },
{ &hf_stringi_char_set, { "Char Set", "cip.stringi.char_set", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } },
{ &hf_stringi_international_string, { "International String", "cip.stringi.int_string", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } },
{ &hf_file_filename, { "File Name", "cip.file.file_name", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } },
{ &hf_time_sync_ptp_enable, { "PTP Enable", "cip.time_sync.ptp_enable", FT_BOOLEAN, 8, TFS(&tfs_enabled_disabled), 0, NULL, HFILL }},
{ &hf_time_sync_is_synchronized, { "Is Synchronized", "cip.time_sync.is_synchronized", FT_BOOLEAN, 8, TFS(&tfs_true_false), 0, NULL, HFILL }},

View File

@ -258,6 +258,7 @@ enum cip_datatype {
cip_short_string,
cip_string,
cip_string2,
cip_stringi,
cip_byte,
cip_byte_array,
cip_word,
@ -270,7 +271,6 @@ enum cip_datatype {
/* Currently not supported */
cip_stringN,
cip_stringi
};
typedef int attribute_dissector_func(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb,
@ -337,6 +337,15 @@ extern void dissect_epath( tvbuff_t *tvb, packet_info *pinfo, proto_tree *path_t
gboolean generate, gboolean packed, cip_simple_request_info_t* req_data, cip_safety_epath_info_t* safety,
int display_type, proto_item *msp_item,
gboolean is_msp_item);
// Elementary Data Types.
enum cip_elem_data_types {
CIP_STRING_TYPE = 0xD0,
CIP_SHORT_STRING_TYPE = 0xDA,
CIP_STRING2_TYPE = 0xD5
};
extern int dissect_cip_string_type(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb, int offset, int hf_type, int string_type);
extern void dissect_cip_date_and_time(proto_tree *tree, tvbuff_t *tvb, int offset, int hf_datetime);
extern attribute_info_t* cip_get_attribute(guint class_id, guint instance, guint attribute);
extern void dissect_cip_get_attribute_all_rsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,

View File

@ -1455,6 +1455,18 @@ dissect_tcpip_interface_config(packet_info *pinfo, proto_tree *tree, proto_item
return (22+domain_length);
}
static int dissect_tcpip_hostname(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb,
int offset, int total_len _U_)
{
int parsed_len;
parsed_len = dissect_cip_string_type(pinfo, tree, item, tvb, offset, hf_tcpip_hostname, CIP_STRING_TYPE);
/* Add padding. */
parsed_len += parsed_len % 2;
return parsed_len;
}
static int dissect_tcpip_ssn(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb,
int offset, int total_len)
{
@ -2057,7 +2069,7 @@ attribute_info_t enip_attribute_vals[99] = {
{0xF5, FALSE, 3, 2, "Configuration Control", cip_dissector_func, NULL, dissect_tcpip_config_control},
{0xF5, FALSE, 4, 3, "Physical Link Object", cip_dissector_func, NULL, dissect_tcpip_physical_link},
{0xF5, FALSE, 5, 4, "Interface Configuration", cip_dissector_func, NULL, dissect_tcpip_interface_config},
{0xF5, FALSE, 6, 5, "Host Name", cip_string, &hf_tcpip_hostname, NULL},
{0xF5, FALSE, 6, 5, "Host Name", cip_dissector_func, NULL, dissect_tcpip_hostname},
{0xF5, FALSE, 7, 6, "Safety Network Number", cip_dissector_func, NULL, dissect_tcpip_ssn},
{0xF5, FALSE, 8, 7, "TTL Value", cip_usint, &hf_tcpip_ttl_value, NULL},
{0xF5, FALSE, 9, 8, "Multicast Configuration", cip_dissector_func, NULL, dissect_tcpip_mcast_config},