wireshark/epan/dissectors/packet-pcomtcp.c

758 lines
29 KiB
C

/* packet-pcomtcp.c
* Routines for PCOM/TCP dissection
* Copyright 2018, Luis Rosa <lmrosa@dei.uc.pt>
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
/*
* PCOM is a protocol to communicate with Unitronics PLCs either by serial or TCP.
* Two modes are available, ASCII and Binary.
*
* See https://unitronicsplc.com/Download/SoftwareUtilities/Unitronics%20PCOM%20Protocol.pdf
*
*/
#include <config.h>
#include <epan/packet.h>
#include <epan/expert.h>
void proto_reg_handoff_pcomtcp(void);
void proto_register_pcomtcp(void);
/* Initialize the protocol and registered fields */
static int proto_pcomtcp = -1;
static int proto_pcomascii = -1;
static int proto_pcombinary = -1;
static int hf_pcomtcp_transid = -1;
static int hf_pcomtcp_protocol = -1;
static int hf_pcomtcp_reserved = -1;
static int hf_pcomtcp_length = -1;
static int hf_pcomascii_stx = -1;
static int hf_pcomascii_unitid = -1;
static int hf_pcomascii_command_code = -1;
static int hf_pcomascii_address = -1;
static int hf_pcomascii_length = -1;
static int hf_pcomascii_address_value = -1;
static int hf_pcomascii_command = -1;
static int hf_pcomascii_checksum = -1;
static int hf_pcomascii_etx = -1;
static int hf_pcombinary_stx = -1;
static int hf_pcombinary_id = -1;
static int hf_pcombinary_reserved1 = -1;
static int hf_pcombinary_reserved2 = -1;
static int hf_pcombinary_reserved3 = -1;
static int hf_pcombinary_command = -1;
static int hf_pcombinary_reserved4 = -1;
static int hf_pcombinary_command_specific = -1;
static int hf_pcombinary_data_length = -1;
static int hf_pcombinary_header_checksum = -1;
static int hf_pcombinary_data = -1;
static int hf_pcombinary_footer_checksum = -1;
static int hf_pcombinary_etx = -1;
static expert_field ei_pcomtcp_reserved_bad_value = EI_INIT;
static expert_field ei_pcomascii_command_unsupported = EI_INIT;
static expert_field ei_pcombinary_reserved1_bad_value = EI_INIT;
static expert_field ei_pcombinary_reserved2_bad_value = EI_INIT;
static expert_field ei_pcombinary_reserved3_bad_value = EI_INIT;
static expert_field ei_pcombinary_reserved4_bad_value = EI_INIT;
static expert_field ei_pcombinary_command_unsupported = EI_INIT;
/* Initialize the subtree pointers */
static gint ett_pcomtcp = -1;
static gint ett_pcomascii = -1;
static gint ett_pcombinary = -1;
static dissector_handle_t pcomtcp_handle;
static dissector_handle_t pcomascii_handle;
static dissector_handle_t pcombinary_handle;
/* PCOM/TCP definitions */
#define PCOMTCP_MIN_LENGTH 6
#define PCOMTCP_TCP_PORT 20256
#define PCOM_ASCII 101
#define PCOM_BINARY 102
static guint global_pcomtcp_tcp_port = PCOMTCP_TCP_PORT; /* Port 20256, by default */
/* Translate pcomp_protocol to string */
static const value_string pcomp_protocol_vals[] = {
{ PCOM_ASCII, "ASCII mode" },
{ PCOM_BINARY, "Binary mode" },
{ 0, NULL },
};
#define PCOMASCII_ID_COMMAND 0x4944 // "ID"
#define PCOMASCII_START_COMMAND 0x434352 // "CCR"
#define PCOMASCII_STOP_COMMAND 0x434353 // "CCS"
#define PCOMASCII_RESET_COMMAND 0x434345 // "CCE"
#define PCOMASCII_INIT_COMMAND 0x434349 // "CCI"
#define PCOMASCII_REPLY_ADMIN_COMMAND 0x4343 // "CC"
#define PCOMASCII_GET_UNITID 0x5547 // "UG"
#define PCOMASCII_SET_UNITID 0x5553 // "US"
#define PCOMASCII_GET_RTC 0x5243 // "RC"
#define PCOMASCII_SET_RTC 0x5343 // "SC"
#define PCOMASCII_READ_INPUTS 0x5245 // "RE"
#define PCOMASCII_READ_OUTPUTS 0x5241 // "RA"
#define PCOMASCII_READ_SYSTEM_BITS 0x4753 // "GS"
#define PCOMASCII_READ_SYSTEM_INTEGERS 0x4746 // "GF"
#define PCOMASCII_READ_SYSTEM_LONGS 0x524e48 // "RNH"
#define PCOMASCII_READ_SYSTEM_DOUBLE_WORDS 0x524e4a // "RNJ"
#define PCOMASCII_READ_MEMORY_BITS 0x5242 // "RB"
#define PCOMASCII_READ_MEMORY_INTEGERS 0x5257 // "RW"
#define PCOMASCII_READ_MEMORY_LONGS 0x524e4c // "RNL"
#define PCOMASCII_READ_MEMORY_DOUBLE_WORDS 0x524e44 // "RND"
#define PCOMASCII_READ_LONGS 0x524e // "RN"
#define PCOMASCII_WRITE_OUTPUTS 0x5341 // "SA"
#define PCOMASCII_WRITE_SYSTEM_BITS 0x5353 // "SS"
#define PCOMASCII_WRITE_SYSTEM_INTEGERS 0x5346 // "SF"
#define PCOMASCII_WRITE_SYSTEM_LONGS 0x534e48 // "SNH"
#define PCOMASCII_WRITE_SYSTEM_DOUBLE_WORDS 0x534e4a // "SNJ"
#define PCOMASCII_WRITE_MEMORY_BITS 0x5342 // "SB"
#define PCOMASCII_WRITE_MEMORY_INTEGERS 0x5357 // "SW"
#define PCOMASCII_WRITE_MEMORY_LONGS 0x534e4c // "SNL"
#define PCOMASCII_WRITE_MEMORY_DOUBLE_WORDS 0x534e44 // "SND"
#define PCOMASCII_WRITE_LONGS 0x534e // "SN"
#define PCOMBINARY_GET_PLC_NAME_REQUEST 0x0c
#define PCOMBINARY_GET_PLC_NAME_REPLY 0x8c
#define PCOMBINARY_READ_OPERANDS_REQUEST 0x4d
#define PCOMBINARY_READ_OPERANDS_REPLY 0xcd
#define PCOMBINARY_READ_DATA_TABLE_REQUEST 0x04
#define PCOMBINARY_READ_DATA_TABLE_REPLY 0x84
#define PCOMBINARY_WRITE_DATA_TABLE_REQUEST 0x44
#define PCOMBINARY_WRITE_DATA_TABLE_REPLY 0xc4
/* Translate pcomascii_command_code to string */
static const value_string pcomascii_cc_vals[] = {
{ PCOMASCII_ID_COMMAND, "Send Identification Command" },
{ PCOMASCII_START_COMMAND, "Send Start Command" },
{ PCOMASCII_STOP_COMMAND, "Send Stop Command" },
{ PCOMASCII_RESET_COMMAND, "Send Reset Command" },
{ PCOMASCII_INIT_COMMAND, "Send Init Command" },
{ PCOMASCII_REPLY_ADMIN_COMMAND, "Reply of Admin Commands (CC*)" },
{ PCOMASCII_GET_UNITID, "Get UnitID" },
{ PCOMASCII_SET_UNITID, "Set UnitID" },
{ PCOMASCII_GET_RTC, "Get RTC" },
{ PCOMASCII_SET_RTC, "Set RTC" },
{ PCOMASCII_READ_INPUTS, "Read Inputs" },
{ PCOMASCII_READ_OUTPUTS, "Read Outputs" },
{ PCOMASCII_READ_SYSTEM_BITS, "Read System Bits" },
{ PCOMASCII_READ_SYSTEM_INTEGERS, "Read System Integers" },
{ PCOMASCII_READ_SYSTEM_LONGS, "Read System Longs" },
{ PCOMASCII_READ_SYSTEM_DOUBLE_WORDS, "Read System Double Words" },
{ PCOMASCII_READ_MEMORY_BITS, "Read Memory Bits" },
{ PCOMASCII_READ_MEMORY_INTEGERS, "Read Memory Integers" },
{ PCOMASCII_READ_MEMORY_LONGS, "Read Memory Longs" },
{ PCOMASCII_READ_MEMORY_DOUBLE_WORDS, "Read Memory Double Words" },
{ PCOMASCII_READ_LONGS, "Read Longs / Double Words" },
{ PCOMASCII_WRITE_OUTPUTS, "Write Outputs" },
{ PCOMASCII_WRITE_SYSTEM_BITS, "Write System Bits" },
{ PCOMASCII_WRITE_SYSTEM_INTEGERS, "Write System Integers" },
{ PCOMASCII_WRITE_SYSTEM_LONGS, "Write System Longs" },
{ PCOMASCII_WRITE_SYSTEM_DOUBLE_WORDS,"Write System Double Words" },
{ PCOMASCII_WRITE_MEMORY_BITS, "Write Memory Bits" },
{ PCOMASCII_WRITE_MEMORY_INTEGERS, "Write Memory Integers" },
{ PCOMASCII_WRITE_MEMORY_LONGS, "Write Memory Longs" },
{ PCOMASCII_WRITE_MEMORY_DOUBLE_WORDS,"Write Memory Double Words" },
{ PCOMASCII_WRITE_LONGS, "Write Longs / Double Words" },
{ 0, NULL },
};
/* Translate pcombinary_command requests to string */
static const value_string pcombinary_command_vals_request[] = {
{ PCOMBINARY_GET_PLC_NAME_REQUEST, "Get PLC Name Request" },
{ PCOMBINARY_READ_OPERANDS_REQUEST, "Read Operands Request" },
{ PCOMBINARY_READ_DATA_TABLE_REQUEST, "Read Data Table Request" },
{ PCOMBINARY_WRITE_DATA_TABLE_REQUEST, "Write Data Table Request" },
{ 0, NULL },
};
/* Translate pcombinary_command reply to string */
static const value_string pcombinary_command_vals_reply[] = {
{ PCOMBINARY_GET_PLC_NAME_REPLY, "Get PLC Name Reply" },
{ PCOMBINARY_READ_OPERANDS_REPLY, "Read Operands Reply" },
{ PCOMBINARY_READ_DATA_TABLE_REPLY, "Read Data Table Reply" },
{ PCOMBINARY_WRITE_DATA_TABLE_REPLY, "Write Data Table Reply" },
{ 0, NULL },
};
/* Code to actually dissect the packets */
static int
dissect_pcomtcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
void *data _U_)
{
/* Set up structures needed to add the protocol subtree and manage it */
proto_item *ti;
proto_tree *pcomtcp_tree;
tvbuff_t *next_tvb;
guint offset = 0;
const char *pkt_type = "";
guint8 pcom_mode;
const char *pcom_mode_str = "";
proto_item *hf_pcomtcp_reserved_item = NULL;
/* Check that the packet is long enough for it to belong to us. */
if (tvb_reported_length(tvb) < PCOMTCP_MIN_LENGTH)
return 0;
pcom_mode = tvb_get_guint8(tvb, 2);
if ( pcom_mode != PCOM_ASCII && pcom_mode != PCOM_BINARY )
return 0;
pcom_mode_str = val_to_str(pcom_mode, pcomp_protocol_vals, "Unknown mode (%d)");
if (pinfo->srcport == global_pcomtcp_tcp_port )
pkt_type = "Reply";
else
pkt_type = "Query";
col_set_str(pinfo->cinfo, COL_PROTOCOL, "PCOM/TCP");
col_clear(pinfo->cinfo, COL_INFO);
col_add_fstr(pinfo->cinfo, COL_INFO, "%s in %s",
pkt_type, pcom_mode_str);
/* create display subtree for the protocol */
ti = proto_tree_add_item(tree, proto_pcomtcp, tvb, 0, -1, ENC_NA);
pcomtcp_tree = proto_item_add_subtree(ti, ett_pcomtcp);
proto_tree_add_item(pcomtcp_tree, hf_pcomtcp_transid, tvb,
offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
proto_tree_add_item(pcomtcp_tree, hf_pcomtcp_protocol, tvb,
offset, 1, ENC_NA);
offset += 1;
hf_pcomtcp_reserved_item = proto_tree_add_item(pcomtcp_tree, hf_pcomtcp_reserved, tvb,
offset, 1, ENC_NA);
if(tvb_get_guint8(tvb, offset) !=0){
expert_add_info_format(pinfo, hf_pcomtcp_reserved_item,
&ei_pcomtcp_reserved_bad_value,"Isn't 0");
}
offset += 1;
proto_tree_add_item(pcomtcp_tree, hf_pcomtcp_length, tvb,
offset, 2, ENC_LITTLE_ENDIAN);
/* dissect the PCOM Data */
offset += 2;
next_tvb = tvb_new_subset_remaining(tvb, offset);
if( tvb_reported_length_remaining(tvb, offset) > 0 ){
if ( pcom_mode == PCOM_ASCII)
call_dissector_with_data(pcomascii_handle, next_tvb, pinfo, tree, &pcom_mode);
else
call_dissector_with_data(pcombinary_handle, next_tvb, pinfo, tree, &pcom_mode);
}
return tvb_reported_length(tvb);
}
static int
dissect_pcomascii(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
void *data _U_)
{
/* Set up structures needed to add the protocol subtree and manage it */
proto_item *ti;
proto_tree *pcomascii_tree;
proto_item *hf_pcomascii_command_item = NULL;
guint offset = 0;
guint16 nvalues;
guint8 i;
guint8 cc_len;
guint32 cc;
const gchar* cc_str;
const gchar* cc_str2;
guint8 op_type;
guint8 op_size;
/* Create protocol tree */
ti = proto_tree_add_item(tree, proto_pcomascii, tvb, offset, -1, ENC_NA);
pcomascii_tree = proto_item_add_subtree(ti, ett_pcomascii);
if (pinfo->srcport == global_pcomtcp_tcp_port ){ // Reply
proto_tree_add_item(pcomascii_tree, hf_pcomascii_stx, tvb,
offset, 2, ENC_ASCII|ENC_NA); // "/A"
offset += 2;
}else{
proto_tree_add_item(pcomascii_tree, hf_pcomascii_stx, tvb,
offset, 1, ENC_ASCII|ENC_NA); // "/"
offset += 1;
}
proto_tree_add_item(pcomascii_tree, hf_pcomascii_unitid, tvb,
offset, 2, ENC_ASCII|ENC_NA);
offset += 2;
// CCs can be 2 or 3 hex chars
cc = tvb_get_ntoh24(tvb, offset);
cc_str = try_val_to_str(cc, pcomascii_cc_vals);
if ( cc_str != NULL && pinfo->srcport != global_pcomtcp_tcp_port ){
cc_len = 3;
}else {
cc = tvb_get_ntohs(tvb, offset);
cc_str = try_val_to_str(cc, pcomascii_cc_vals);
if (cc_str != NULL ){
cc_len = 2;
}else{
cc_len = 0;
}
}
if ( cc_len > 0 ){
cc_str2 = tvb_get_string_enc(pinfo->pool, tvb, offset, cc_len, ENC_ASCII);
proto_tree_add_string_format_value(pcomascii_tree,
hf_pcomascii_command_code, tvb, offset, cc_len,
cc_str2, "%s (%s)", cc_str, cc_str2);
offset += cc_len;
switch(cc)
{
case PCOMASCII_READ_INPUTS:
case PCOMASCII_READ_OUTPUTS:
case PCOMASCII_READ_SYSTEM_BITS:
case PCOMASCII_READ_MEMORY_BITS:
op_type = 1; // read operation
op_size = 1; // 1 char per operand
break;
case PCOMASCII_READ_SYSTEM_INTEGERS:
case PCOMASCII_READ_MEMORY_INTEGERS:
op_type = 1; // read operation
op_size = 4; // 4 chars per operand
break;
case PCOMASCII_READ_SYSTEM_LONGS:
case PCOMASCII_READ_MEMORY_LONGS:
case PCOMASCII_READ_SYSTEM_DOUBLE_WORDS:
case PCOMASCII_READ_MEMORY_DOUBLE_WORDS:
case PCOMASCII_READ_LONGS:
op_type = 1; // read operation
op_size = 8; // 8 chars per operand
break;
case PCOMASCII_WRITE_OUTPUTS:
case PCOMASCII_WRITE_SYSTEM_BITS:
case PCOMASCII_WRITE_MEMORY_BITS:
op_type = 2; // write operation
op_size = 1; // 1 char per operand
break;
case PCOMASCII_WRITE_SYSTEM_INTEGERS:
case PCOMASCII_WRITE_MEMORY_INTEGERS:
op_type = 2; // write operation
op_size = 4; // 4 chars per operand
break;
case PCOMASCII_WRITE_MEMORY_LONGS:
case PCOMASCII_WRITE_SYSTEM_LONGS:
case PCOMASCII_WRITE_SYSTEM_DOUBLE_WORDS:
case PCOMASCII_WRITE_MEMORY_DOUBLE_WORDS:
case PCOMASCII_WRITE_LONGS:
op_type = 2; // write operation
op_size = 8; // 8 chars per operand
break;
default:
op_type = 0;
op_size = 0;
break;
}
if(pinfo->destport == global_pcomtcp_tcp_port){ // request
if(op_type == 1 || op_type == 2) { // read & write op
proto_tree_add_item(pcomascii_tree, hf_pcomascii_address,
tvb, offset, 4, ENC_ASCII|ENC_NA);
offset += 4;
proto_tree_add_item(pcomascii_tree, hf_pcomascii_length,
tvb, offset, 2, ENC_ASCII|ENC_NA);
offset += 2;
}
if(op_type == 2) { // write only
nvalues = (tvb_reported_length(tvb)-3-offset) / op_size;
for (i = 0; i < nvalues; i++) {
proto_tree_add_item(pcomascii_tree, hf_pcomascii_address_value,
tvb, offset, op_size , ENC_ASCII|ENC_NA);
offset += op_size;
}
}
} else { // reply
if(op_type == 1) { // read only
nvalues = (tvb_reported_length(tvb)-offset-3) / op_size;
for (i = 0; i < nvalues; i++) {
proto_tree_add_item(pcomascii_tree, hf_pcomascii_address_value,
tvb, offset, op_size , ENC_ASCII|ENC_NA);
offset += op_size;
}
}
}
}
if (tvb_reported_length(tvb)-offset-3 > 0){ // remaining (variable) bytes between CC and checksum
hf_pcomascii_command_item = proto_tree_add_item(pcomascii_tree, hf_pcomascii_command, tvb,
offset, tvb_reported_length(tvb)-offset-3, ENC_ASCII|ENC_NA);
offset += (tvb_reported_length(tvb)-offset-3); //-3 from checksum and etx
if(cc_len <= 0){
expert_add_info_format(pinfo, hf_pcomascii_command_item,
&ei_pcomascii_command_unsupported, "Unsupported Command");
}
}
proto_tree_add_item(pcomascii_tree, hf_pcomascii_checksum, tvb,
offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
proto_tree_add_item(pcomascii_tree, hf_pcomascii_etx, tvb,
offset, 1, ENC_ASCII|ENC_NA);
return tvb_reported_length(tvb);
}
static int
dissect_pcombinary(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
void *data _U_)
{
/* Set up structures needed to add the protocol subtree and manage it */
proto_item *ti;
proto_tree *pcombinary_tree;
guint offset = 0;
proto_item *hf_pcombinary_reserved1_item = NULL;
proto_item *hf_pcombinary_reserved2_item = NULL;
proto_item *hf_pcombinary_reserved3_item = NULL;
proto_item *hf_pcombinary_reserved4_item = NULL;
proto_item *hf_pcombinary_command_item = NULL;
guint8 command;
const gchar* command_str;
/* Create protocol tree */
ti = proto_tree_add_item(tree, proto_pcombinary, tvb, offset, -1, ENC_NA);
pcombinary_tree = proto_item_add_subtree(ti, ett_pcombinary);
proto_tree_add_item(pcombinary_tree, hf_pcombinary_stx, tvb,
offset, 6, ENC_ASCII|ENC_NA);
offset += 6;
if (pinfo->srcport == global_pcomtcp_tcp_port){ //these bytes are transposed
hf_pcombinary_reserved1_item = proto_tree_add_item(pcombinary_tree,
hf_pcombinary_reserved1, tvb, offset, 1, ENC_NA);
if(tvb_get_guint8(tvb, offset) !=254){
expert_add_info_format(pinfo, hf_pcombinary_reserved1_item,
&ei_pcombinary_reserved1_bad_value,"Isn't 0xfe");
}
offset += 1;
proto_tree_add_item(pcombinary_tree, hf_pcombinary_id, tvb,
offset, 1, ENC_NA);
offset += 1;
}else{
proto_tree_add_item(pcombinary_tree, hf_pcombinary_id, tvb,
offset, 1, ENC_NA);
offset += 1;
proto_tree_add_item(pcombinary_tree, hf_pcombinary_reserved1, tvb,
offset, 1, ENC_NA);
offset += 1;
}
hf_pcombinary_reserved2_item = proto_tree_add_item(pcombinary_tree,
hf_pcombinary_reserved2, tvb, offset, 1, ENC_NA);
if( tvb_get_guint8(tvb, offset) !=1)
expert_add_info_format(pinfo, hf_pcombinary_reserved2_item,
&ei_pcombinary_reserved2_bad_value,"Isn't 1");
offset += 1;
hf_pcombinary_reserved3_item = proto_tree_add_item(pcombinary_tree,
hf_pcombinary_reserved3, tvb, offset, 3, ENC_LITTLE_ENDIAN);
if( tvb_get_letoh24(tvb,offset) != 0)
expert_add_info_format(pinfo, hf_pcombinary_reserved3_item,
&ei_pcombinary_reserved3_bad_value,"Isn't 0");
offset += 3;
command = tvb_get_guint8(tvb, offset);
if(pinfo->srcport == global_pcomtcp_tcp_port){ // reply
command_str = try_val_to_str(command, pcombinary_command_vals_reply);
}else{
command_str = try_val_to_str(command, pcombinary_command_vals_request);
}
if ( command_str != NULL ) {
proto_tree_add_uint_format_value(pcombinary_tree,
hf_pcombinary_command, tvb, offset, 1,
command, "%s (%02x)", command_str, command);
}else{
hf_pcombinary_command_item = proto_tree_add_item(pcombinary_tree, hf_pcombinary_command, tvb,
offset, 1, ENC_NA);
expert_add_info_format(pinfo, hf_pcombinary_command_item,
&ei_pcombinary_command_unsupported,"Unsupported Command");}
offset += 1;
hf_pcombinary_reserved4_item = proto_tree_add_item(pcombinary_tree,
hf_pcombinary_reserved4, tvb, offset, 1, ENC_NA);
if( tvb_get_guint8(tvb, offset) !=0)
expert_add_info_format(pinfo, hf_pcombinary_reserved4_item,
&ei_pcombinary_reserved4_bad_value,"Isn't 0");
offset += 1;
proto_tree_add_item(pcombinary_tree, hf_pcombinary_command_specific, tvb,
offset, 6, ENC_NA);
offset += 6;
proto_tree_add_item(pcombinary_tree, hf_pcombinary_data_length, tvb,
offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
proto_tree_add_item(pcombinary_tree, hf_pcombinary_header_checksum, tvb,
offset, 2, ENC_NA);
offset += 2;
if ((tvb_reported_length(tvb) - 27) > 0) // ( -3 footer - 24 header)
proto_tree_add_item(pcombinary_tree, hf_pcombinary_data, tvb,
offset, tvb_reported_length(tvb)-27, ENC_NA);
offset += (tvb_reported_length(tvb)-27);
proto_tree_add_item(pcombinary_tree, hf_pcombinary_footer_checksum, tvb,
offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
proto_tree_add_item(pcombinary_tree, hf_pcombinary_etx, tvb,
offset, 1, ENC_ASCII|ENC_NA);
return tvb_reported_length(tvb);
}
static void
apply_pcomtcp_prefs(void)
{
global_pcomtcp_tcp_port = prefs_get_uint_value("pcomtcp", "tcp.port");
}
void
proto_register_pcomtcp(void)
{
static hf_register_info hf_pcomtcp[] = {
{ &hf_pcomtcp_transid,
{ "Transaction Identifier", "pcomtcp.trans_id",
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_pcomtcp_protocol,
{ "Protocol Mode", "pcomtcp.protocol",
FT_UINT8, BASE_DEC, VALS(pcomp_protocol_vals), 0x0,
NULL, HFILL }
},
{ &hf_pcomtcp_reserved,
{ "Reserved", "pcomtcp.reserved",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_pcomtcp_length,
{ "Length (bytes)", "pcomtcp.length",
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
};
static hf_register_info hf_pcomascii[] = {
{ &hf_pcomascii_stx,
{ "STX", "pcomascii.stx",
FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
{ &hf_pcomascii_unitid,
{ "Unit Identifier", "pcomascii.unitid",
FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL }
},
{ &hf_pcomascii_command_code,
{ "Command Code", "pcomascii.command_code",
FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
{ &hf_pcomascii_address,
{ "Address", "pcomascii.address",
FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
{ &hf_pcomascii_length,
{ "Length", "pcomascii.length",
FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
{ &hf_pcomascii_address_value,
{ "Address Value", "pcomascii.address_value",
FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
{ &hf_pcomascii_command,
{ "Command", "pcomascii.command",
FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
{ &hf_pcomascii_checksum,
{ "Checksum", "pcomascii.checksum",
FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL }
},
{ &hf_pcomascii_etx,
{ "ETX", "pcomascii.etx",
FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
};
static hf_register_info hf_pcombinary[] = {
{ &hf_pcombinary_stx,
{ "STX", "pcombinary.stx",
FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
{ &hf_pcombinary_id,
{ "ID (CANBUS or RS485)", "pcombinary.id",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_pcombinary_reserved1,
{ "Reserved", "pcombinary.reserved1",
FT_UINT8, BASE_HEX, NULL, 0x0,
NULL, HFILL }
},
{ &hf_pcombinary_reserved2,
{ "Reserved", "pcombinary.reserved2",
FT_UINT8, BASE_HEX, NULL, 0x0,
NULL, HFILL }
},
{ &hf_pcombinary_reserved3,
{ "Reserved", "pcombinary.reserved3",
FT_UINT8, BASE_HEX, NULL, 0x0,
NULL, HFILL }
},
{ &hf_pcombinary_command,
{ "Command", "pcombinary.command",
FT_UINT8, BASE_HEX, NULL, 0x0,
NULL, HFILL }
},
{ &hf_pcombinary_reserved4,
{ "Reserved", "pcombinary.reserved0",
FT_UINT8, BASE_HEX, NULL, 0x0,
NULL, HFILL }
},
{ &hf_pcombinary_command_specific,
{ "Command Details", "pcombinary.command_specific",
FT_BYTES, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
{ &hf_pcombinary_data_length,
{ "Data Length", "pcombinary.data_length",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_pcombinary_header_checksum,
{ "(Header) Checksum", "pcombinary.header_checksum",
FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL }
},
{ &hf_pcombinary_data,
{ "Data", "pcombinary.data",
FT_BYTES, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
{ &hf_pcombinary_footer_checksum,
{ "(Footer) Checksum", "pcombinary.footer_checksum",
FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL }
},
{ &hf_pcombinary_etx,
{ "ETX", "pcombinary.etx",
FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
};
/* Setup protocol subtree array */
static gint *ett[] = {
&ett_pcomtcp,
&ett_pcomascii,
&ett_pcombinary
};
static ei_register_info pcomtcp_ei[] = {
{ &ei_pcomtcp_reserved_bad_value,
{ "pcombinary.reserved.bad_value", PI_PROTOCOL, PI_WARN,
"Isn't 0", EXPFILL }
},
};
static ei_register_info pcombinary_ei[] = {
{ &ei_pcombinary_reserved1_bad_value,
{ "pcombinary.reserved1.bad_value", PI_PROTOCOL, PI_WARN,
"Isn't 0xfe", EXPFILL }
},
{ &ei_pcombinary_reserved2_bad_value,
{ "pcombinary.reserved2.bad_value", PI_PROTOCOL, PI_WARN,
"Isn't 1", EXPFILL }
},
{ &ei_pcombinary_reserved3_bad_value,
{ "pcombinary.reserved3.bad_value", PI_PROTOCOL, PI_WARN,
"Isn't 0", EXPFILL }
},
{ &ei_pcombinary_reserved4_bad_value,
{ "pcombinary.reserved4.bad_value", PI_PROTOCOL, PI_WARN,
"Isn't 0", EXPFILL }
},
{ &ei_pcombinary_command_unsupported,
{ "pcombinary.command.unsupported", PI_PROTOCOL, PI_WARN,
"Unsupported Command", EXPFILL }
},
};
static ei_register_info pcomascii_ei[] = {
{ &ei_pcomascii_command_unsupported,
{ "pcomascii.command.unsupported", PI_PROTOCOL, PI_WARN,
"Unsupported Command", EXPFILL }
},
};
expert_module_t* expert_pcomtcp;
expert_module_t* expert_pcomascii;
expert_module_t* expert_pcombinary;
/* Register the protocol name and description */
proto_pcomtcp = proto_register_protocol("PCOM/TCP","PCOM/TCP", "pcomtcp");
proto_pcomascii = proto_register_protocol("PCOM ASCII","PCOM ASCII", "pcomascii");
proto_pcombinary = proto_register_protocol("PCOM BINARY","PCOM BINARY", "pcombinary");
pcomtcp_handle = register_dissector("pcomtcp", dissect_pcomtcp, proto_pcomtcp);
pcomascii_handle = register_dissector("pcomascii", dissect_pcomascii, proto_pcomascii);
pcombinary_handle = register_dissector("pcombinary", dissect_pcombinary, proto_pcombinary);
/* Required function calls to register the header fields and subtrees */
proto_register_field_array(proto_pcomtcp, hf_pcomtcp, array_length(hf_pcomtcp));
proto_register_field_array(proto_pcomascii, hf_pcomascii, array_length(hf_pcomascii));
proto_register_field_array(proto_pcombinary, hf_pcombinary, array_length(hf_pcombinary));
proto_register_subtree_array(ett, array_length(ett));
expert_pcomtcp = expert_register_protocol(proto_pcomtcp);
expert_pcomascii = expert_register_protocol(proto_pcomascii);
expert_pcombinary = expert_register_protocol(proto_pcombinary);
expert_register_field_array(expert_pcomtcp, pcomtcp_ei, array_length(pcomtcp_ei));
expert_register_field_array(expert_pcomascii, pcomascii_ei, array_length(pcomascii_ei));
expert_register_field_array(expert_pcombinary, pcombinary_ei, array_length(pcombinary_ei));
prefs_register_protocol(proto_pcomtcp, apply_pcomtcp_prefs);
}
void
proto_reg_handoff_pcomtcp(void)
{
dissector_add_uint_with_preference("tcp.port", PCOMTCP_TCP_PORT, pcomtcp_handle);
}
/*
* Editor modelines - https://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:
*/