[SELFM] Fix reassembly, tcp_dissect_pdus() can't be used as the real
length of the PDU is not known(length is exluding escape bytes). Change-Id: I762419f12ca80f6597163e232c4b853819927b65 Reviewed-on: https://code.wireshark.org/review/17302 Petri-Dish: Anders Broman <a.broman58@gmail.com> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Anders Broman <a.broman58@gmail.com>
This commit is contained in:
parent
4fe91cf9f5
commit
2e42199e11
1 changed files with 85 additions and 56 deletions
|
@ -70,7 +70,9 @@
|
|||
#include <epan/expert.h>
|
||||
#include <epan/crc16-tvb.h>
|
||||
#include <epan/proto_data.h>
|
||||
|
||||
#if 0
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
void proto_register_selfm(void);
|
||||
|
||||
/* Initialize the protocol and registered fields */
|
||||
|
@ -826,18 +828,17 @@ static const fragment_items selfm_frag_items = {
|
|||
/* Function Duplicated from packet-telnet.c (unescape_and_tvbuffify_telnet_option) */
|
||||
/**********************************************************************************************************/
|
||||
static tvbuff_t *
|
||||
clean_telnet_iac(packet_info *pinfo, tvbuff_t *tvb, int offset, int len)
|
||||
clean_telnet_iac(packet_info *pinfo, tvbuff_t *tvb, int offset, int len, int *num_skip_byte)
|
||||
{
|
||||
tvbuff_t *telnet_tvb;
|
||||
guint8 *buf;
|
||||
const guint8 *spos;
|
||||
guint8 *dpos;
|
||||
int skip_byte, len_remaining;
|
||||
int len_remaining, skip_byte = 0;
|
||||
|
||||
spos=tvb_get_ptr(tvb, offset, len);
|
||||
buf=(guint8 *)wmem_alloc(pinfo->pool, len);
|
||||
dpos=buf;
|
||||
skip_byte = 0;
|
||||
len_remaining = len;
|
||||
while(len_remaining > 0){
|
||||
|
||||
|
@ -860,6 +861,8 @@ clean_telnet_iac(packet_info *pinfo, tvbuff_t *tvb, int offset, int len)
|
|||
telnet_tvb = tvb_new_child_real_data(tvb, buf, len-skip_byte, len-skip_byte);
|
||||
add_new_data_source(pinfo, telnet_tvb, "Processed Telnet Data");
|
||||
|
||||
*num_skip_byte = skip_byte;
|
||||
|
||||
return telnet_tvb;
|
||||
}
|
||||
|
||||
|
@ -1105,8 +1108,9 @@ dissect_relaydef_frame(tvbuff_t *tvb, proto_tree *tree, int offset)
|
|||
}
|
||||
|
||||
proto_tree_add_checksum(relaydef_tree, tvb, offset, hf_selfm_checksum, -1, NULL, NULL, 0, ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS);
|
||||
offset += 1;
|
||||
|
||||
return tvb_reported_length(tvb);
|
||||
return offset;
|
||||
}
|
||||
|
||||
/******************************************************************************************************/
|
||||
|
@ -1209,8 +1213,9 @@ dissect_fmconfig_frame(tvbuff_t *tvb, proto_tree *tree, int offset)
|
|||
}
|
||||
|
||||
proto_tree_add_checksum(fmconfig_tree, tvb, offset, hf_selfm_checksum, -1, NULL, NULL, 0, ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS);
|
||||
offset += 1;
|
||||
|
||||
return tvb_reported_length(tvb);
|
||||
return offset;
|
||||
|
||||
}
|
||||
|
||||
|
@ -1425,6 +1430,7 @@ dissect_fmdata_frame(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, int of
|
|||
}
|
||||
|
||||
proto_tree_add_checksum(fmdata_tree, tvb, offset, hf_selfm_checksum, -1, NULL, pinfo, 0, ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS);
|
||||
offset += 1;
|
||||
|
||||
} /* matching config frame message was found */
|
||||
|
||||
|
@ -1432,11 +1438,12 @@ dissect_fmdata_frame(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, int of
|
|||
|
||||
if (!config_found) {
|
||||
proto_item_append_text(fmdata_item, ", No Fast Meter Configuration frame found");
|
||||
return 0;
|
||||
offset += (len-2);
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
|
||||
return tvb_reported_length(tvb);
|
||||
return offset;
|
||||
|
||||
}
|
||||
|
||||
|
@ -1518,8 +1525,9 @@ dissect_foconfig_frame(tvbuff_t *tvb, proto_tree *tree, int offset)
|
|||
}
|
||||
|
||||
proto_tree_add_checksum(foconfig_tree, tvb, offset, hf_selfm_checksum, -1, NULL, NULL, 0, ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS);
|
||||
offset += 1;
|
||||
|
||||
return tvb_reported_length(tvb);
|
||||
return offset;
|
||||
|
||||
}
|
||||
|
||||
|
@ -1559,7 +1567,9 @@ dissect_alt_fastop_config_frame(tvbuff_t *tvb, proto_tree *tree, int offset)
|
|||
proto_tree_add_item(foconfig_tree, hf_selfm_alt_foconfig_funccode, tvb, offset+7, 1, ENC_BIG_ENDIAN);
|
||||
proto_tree_add_item(foconfig_tree, hf_selfm_alt_foconfig_funccode, tvb, offset+8, 1, ENC_BIG_ENDIAN);
|
||||
|
||||
return tvb_reported_length(tvb);
|
||||
offset += (len - 2);
|
||||
|
||||
return offset;
|
||||
|
||||
}
|
||||
|
||||
|
@ -1607,8 +1617,9 @@ dissect_fastop_frame(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, int of
|
|||
|
||||
/* Add checksum */
|
||||
proto_tree_add_checksum(fastop_tree, tvb, offset, hf_selfm_checksum, -1, NULL, pinfo, 0, ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS);
|
||||
offset += 1;
|
||||
|
||||
return tvb_reported_length(tvb);
|
||||
return offset;
|
||||
|
||||
}
|
||||
|
||||
|
@ -1643,8 +1654,9 @@ dissect_alt_fastop_frame(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, in
|
|||
|
||||
/* Operate Code Validation */
|
||||
proto_tree_add_item(fastop_tree, hf_selfm_alt_fastop_valid, tvb, offset, 2, ENC_BIG_ENDIAN);
|
||||
offset += 2;
|
||||
|
||||
return tvb_reported_length(tvb);
|
||||
return offset;
|
||||
|
||||
}
|
||||
|
||||
|
@ -2284,10 +2296,10 @@ dissect_fastmsg_frame(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, int o
|
|||
|
||||
/* Some relays (4xx) don't follow the standard here and include an 8-byte sequence of all 0x00's to represent */
|
||||
/* 'reserved' space for the control regions. Detect these and skip if they are present */
|
||||
for (cnt = offset; cnt < len; cnt++) {
|
||||
if (tvb_reported_length_remaining(tvb, offset) > 2) {
|
||||
|
||||
if (tvb_memeql(tvb, cnt, "\x00\x00\x00\x00\x00\x00\x00\x00", 8) == 0) {
|
||||
offset = cnt+8;
|
||||
if (tvb_memeql(tvb, offset, "\x00\x00\x00\x00\x00\x00\x00\x00", 8) == 0) {
|
||||
offset += 8;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2349,6 +2361,7 @@ dissect_fastmsg_frame(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, int o
|
|||
/* Add CRC16 to Tree */
|
||||
fastmsg_crc16_item = proto_tree_add_item(fastmsg_tree, hf_selfm_fastmsg_crc16, tvb, offset, 2, ENC_BIG_ENDIAN);
|
||||
crc16 = tvb_get_ntohs(tvb, offset);
|
||||
offset += 2;
|
||||
|
||||
/* If option is enabled, validate the CRC16 */
|
||||
if (selfm_crc16) {
|
||||
|
@ -2362,7 +2375,7 @@ dissect_fastmsg_frame(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, int o
|
|||
|
||||
}
|
||||
|
||||
return tvb_reported_length(tvb);
|
||||
return offset;
|
||||
|
||||
}
|
||||
|
||||
|
@ -2377,7 +2390,7 @@ dissect_selfm(tvbuff_t *selfm_tvb, packet_info *pinfo, proto_tree *tree, void* d
|
|||
/* Set up structures needed to add the protocol subtree and manage it */
|
||||
proto_item *selfm_item=NULL;
|
||||
proto_tree *selfm_tree=NULL;
|
||||
int offset=0, cnt=0;
|
||||
int offset=0, cnt=0, consumed_bytes=0;
|
||||
guint32 base_addr;
|
||||
guint16 msg_type, len, num_items;
|
||||
guint8 seq, seq_cnt;
|
||||
|
@ -2485,6 +2498,9 @@ dissect_selfm(tvbuff_t *selfm_tvb, packet_info *pinfo, proto_tree *tree, void* d
|
|||
/* Call the same read response function that will be called during GUI dissection */
|
||||
offset = dissect_fastmsg_readresp_frame( selfm_tvb, tree, pinfo, offset, seq);
|
||||
|
||||
/* Skip CRC16 */
|
||||
offset = len;
|
||||
|
||||
}
|
||||
|
||||
/* 4. Fill conversation data array with Fast Message Data Region info from Device Desc Response Messages. This */
|
||||
|
@ -2517,6 +2533,8 @@ dissect_selfm(tvbuff_t *selfm_tvb, packet_info *pinfo, proto_tree *tree, void* d
|
|||
wmem_tree_insert32(fm_conv_data->fastmsg_dataregions, base_address, dataregion_ptr);
|
||||
offset += 18;
|
||||
}
|
||||
|
||||
offset = len;
|
||||
}
|
||||
} /* if (!visited) */
|
||||
|
||||
|
@ -2531,46 +2549,47 @@ dissect_selfm(tvbuff_t *selfm_tvb, packet_info *pinfo, proto_tree *tree, void* d
|
|||
/* Add Message Type to Protocol Tree */
|
||||
proto_tree_add_item(selfm_tree, hf_selfm_msgtype, selfm_tvb, offset, 2, ENC_BIG_ENDIAN);
|
||||
offset += 2;
|
||||
consumed_bytes += 2;
|
||||
|
||||
/* Determine correct message type and call appropriate dissector */
|
||||
if (tvb_reported_length_remaining(selfm_tvb, offset) > 0) {
|
||||
switch (msg_type) {
|
||||
case CMD_RELAY_DEF:
|
||||
dissect_relaydef_frame(selfm_tvb, selfm_tree, offset);
|
||||
consumed_bytes = dissect_relaydef_frame(selfm_tvb, selfm_tree, offset);
|
||||
break;
|
||||
case CMD_FM_CONFIG:
|
||||
case CMD_DFM_CONFIG:
|
||||
case CMD_PDFM_CONFIG:
|
||||
dissect_fmconfig_frame(selfm_tvb, selfm_tree, offset);
|
||||
consumed_bytes = dissect_fmconfig_frame(selfm_tvb, selfm_tree, offset);
|
||||
break;
|
||||
case CMD_FM_DATA:
|
||||
dissect_fmdata_frame(selfm_tvb, selfm_tree, pinfo, offset, CMD_FM_CONFIG);
|
||||
consumed_bytes = dissect_fmdata_frame(selfm_tvb, selfm_tree, pinfo, offset, CMD_FM_CONFIG);
|
||||
break;
|
||||
case CMD_DFM_DATA:
|
||||
dissect_fmdata_frame(selfm_tvb, selfm_tree, pinfo, offset, CMD_DFM_CONFIG);
|
||||
consumed_bytes = dissect_fmdata_frame(selfm_tvb, selfm_tree, pinfo, offset, CMD_DFM_CONFIG);
|
||||
break;
|
||||
case CMD_PDFM_DATA:
|
||||
dissect_fmdata_frame(selfm_tvb, selfm_tree, pinfo, offset, CMD_PDFM_CONFIG);
|
||||
consumed_bytes = dissect_fmdata_frame(selfm_tvb, selfm_tree, pinfo, offset, CMD_PDFM_CONFIG);
|
||||
break;
|
||||
case CMD_FASTOP_CONFIG:
|
||||
dissect_foconfig_frame(selfm_tvb, selfm_tree, offset);
|
||||
consumed_bytes = dissect_foconfig_frame(selfm_tvb, selfm_tree, offset);
|
||||
break;
|
||||
case CMD_FAST_MSG:
|
||||
dissect_fastmsg_frame(selfm_tvb, selfm_tree, pinfo, offset);
|
||||
consumed_bytes = dissect_fastmsg_frame(selfm_tvb, selfm_tree, pinfo, offset);
|
||||
break;
|
||||
case CMD_FASTOP_RB_CTRL:
|
||||
case CMD_FASTOP_BR_CTRL:
|
||||
dissect_fastop_frame(selfm_tvb, selfm_tree, pinfo, offset);
|
||||
consumed_bytes = dissect_fastop_frame(selfm_tvb, selfm_tree, pinfo, offset);
|
||||
break;
|
||||
case CMD_ALT_FASTOP_CONFIG:
|
||||
dissect_alt_fastop_config_frame(selfm_tvb, selfm_tree, offset);
|
||||
consumed_bytes = dissect_alt_fastop_config_frame(selfm_tvb, selfm_tree, offset);
|
||||
break;
|
||||
case CMD_ALT_FASTOP_OPEN:
|
||||
case CMD_ALT_FASTOP_CLOSE:
|
||||
case CMD_ALT_FASTOP_SET:
|
||||
case CMD_ALT_FASTOP_CLEAR:
|
||||
case CMD_ALT_FASTOP_PULSE:
|
||||
dissect_alt_fastop_frame(selfm_tvb, selfm_tree, pinfo, offset);
|
||||
consumed_bytes = dissect_alt_fastop_frame(selfm_tvb, selfm_tree, pinfo, offset);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -2578,39 +2597,20 @@ dissect_selfm(tvbuff_t *selfm_tvb, packet_info *pinfo, proto_tree *tree, void* d
|
|||
} /* remaining length > 0 */
|
||||
}
|
||||
|
||||
return tvb_reported_length(selfm_tvb);
|
||||
return consumed_bytes;
|
||||
}
|
||||
|
||||
/******************************************************************************************************/
|
||||
/* Return length of SEL Protocol over TCP message (used for re-assembly) */
|
||||
/* SEL Protocol "Scan" messages are generally 2-bytes in length and only include a 16-bit message type */
|
||||
/* SEL Protocol "Response" messages include a "length" byte in offset 2 of each response message */
|
||||
/******************************************************************************************************/
|
||||
static guint
|
||||
get_selfm_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset _U_, void *data _U_)
|
||||
{
|
||||
guint message_len=0; /* message length, inclusive of header, data, crc */
|
||||
|
||||
/* Get length byte from message */
|
||||
if (tvb_reported_length(tvb) > 2) {
|
||||
message_len = tvb_get_guint8(tvb, offset+2);
|
||||
}
|
||||
/* for 2-byte poll messages, set the length to 2 */
|
||||
else if (tvb_reported_length(tvb) == 2) {
|
||||
message_len = 2;
|
||||
}
|
||||
|
||||
return message_len;
|
||||
}
|
||||
|
||||
/******************************************************************************************************/
|
||||
/* Dissect (and possibly Re-assemble) SEL protocol payload data */
|
||||
/* Dissect (and possibly Re-assemble) SEL protocol payload data */
|
||||
/* tvb -> selfm_tvb -> selfm_pdu_tvb */
|
||||
/* -> selfm_pdu_tvb */
|
||||
/******************************************************************************************************/
|
||||
static int
|
||||
dissect_selfm_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
|
||||
{
|
||||
|
||||
tvbuff_t *selfm_tvb;
|
||||
tvbuff_t *selfm_tvb, *selfm_pdu_tvb;
|
||||
int skip_byte = 0, selfm_tvb_len, offset = 0;
|
||||
gint length = tvb_reported_length(tvb);
|
||||
|
||||
/* Check for a SEL Protocol packet. It should begin with 0xA5 */
|
||||
|
@ -2619,20 +2619,49 @@ dissect_selfm_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *dat
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (length == 2) {
|
||||
return dissect_selfm(tvb, pinfo, tree, data);
|
||||
}
|
||||
|
||||
/* If the selfm message lenght is greater than the TCP segment, request more data */
|
||||
if (length < tvb_get_guint8(tvb,2)) {
|
||||
pinfo->desegment_offset = 0;
|
||||
pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
|
||||
return tvb_captured_length(tvb);
|
||||
}
|
||||
|
||||
|
||||
/* If this is a Telnet-encapsulated Ethernet packet, let's clean out the IAC 0xFF instances */
|
||||
/* before we attempt any kind of re-assembly of the message */
|
||||
if ((pinfo->srcport) && selfm_telnet_clean) {
|
||||
selfm_tvb = clean_telnet_iac(pinfo, tvb, 0, length);
|
||||
selfm_tvb = clean_telnet_iac(pinfo, tvb, 0, length, &skip_byte);
|
||||
}
|
||||
else {
|
||||
selfm_tvb = tvb_new_subset_length( tvb, 0, length);
|
||||
}
|
||||
|
||||
selfm_tvb_len = tvb_reported_length(selfm_tvb);
|
||||
if (selfm_tvb_len < tvb_get_guint8(tvb, 2)) {
|
||||
pinfo->desegment_offset = 0;
|
||||
pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
|
||||
return tvb_captured_length(tvb);
|
||||
}
|
||||
|
||||
tcp_dissect_pdus(selfm_tvb, pinfo, tree, selfm_desegment, 2,
|
||||
get_selfm_len, dissect_selfm, data);
|
||||
/* If multiple SEL protocol PDUs exist within a single tvb, dissect each of them sequentially */
|
||||
while (offset < selfm_tvb_len) {
|
||||
/* If random ASCII data makes its way onto the end of an SEL protocol PDU, ignore it */
|
||||
if (tvb_get_guint8(selfm_tvb, offset) != 0xA5) {
|
||||
#if 0
|
||||
fprintf(stderr, "On Packet: %d, extraneous data (%x).. \n", pinfo->fd->num, tvb_get_guint8(selfm_tvb, offset));
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
/* In the case of multiple PDUs, create new selfm_pdu_tvb */
|
||||
selfm_pdu_tvb = tvb_new_subset_length( selfm_tvb, offset, tvb_get_guint8(selfm_tvb, offset+2));
|
||||
offset += dissect_selfm(selfm_pdu_tvb, pinfo, tree, data);
|
||||
}
|
||||
|
||||
return length;
|
||||
return selfm_tvb_len + skip_byte;
|
||||
}
|
||||
|
||||
/******************************************************************************************************/
|
||||
|
|
Loading…
Reference in a new issue