I have a strange protocol[1], which can be optionally compressed and then it may also change its PDU structure, after initial negotiations.
I'm using tcp_dissect_pdus().
I found no better way than fetching the conversation with the _get_len() function and checking, based on the saved conversation (saved when created as part of the negotiation) data, determining what the PDU length is. If it's compressed, I decode the length field in some way. If it is switched to 'streaming mode' , another, etc.
It works. But it looks a bit ugly, fetching the conversation every time.
An alternative which is even a bit more absurd (?) is to create sub-dissectors for them?
Here's how it looks like (and works!) right now:
static unsigned
get_scylla_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
{
unsigned int reported_len;
conversation_t *conversation;
scylla_conv_t *scylla_conversation;
if (looks_like_rpc_negotiation(tvb)) {
return tvb_get_letohl(tvb, offset + SCYLLA_NEGOTIATION_LEN_OFFSET) + SCYLLA_NEGOTIATION_SIZE;
}
conversation = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst,
conversation_pt_to_conversation_type(pinfo->ptype),
pinfo->srcport, pinfo->destport, 0);
if (conversation) {
scylla_conversation = (scylla_conv_t *)conversation_get_proto_data(conversation, proto_scylla);
if (scylla_conversation && scylla_conversation->compression) { /* compressed PDU */
return tvb_get_letohl(tvb, offset);
}
} else {
return 0;
}
reported_len = tvb_reported_length(tvb);
if(pinfo->destport == pinfo->match_uint) { /* request */
if (reported_len >= SCYLLA_HEADER_SIZE) {
return tvb_get_letohl(tvb, offset + SCYLLA_HEADER_LEN_OFFSET) + SCYLLA_HEADER_SIZE;
} else {
return 0;
}
} else { /* response */
if (reported_len >= SCYLLA_RESPONSE_SIZE) {
return tvb_get_letohl(tvb, offset + SCYLLA_HEADER_SIZE);
} else {
return 0;
}
}
}
TIA,
Y.