epan: centralize SDNV processing along other similar varint types

This avoids having general-purpose decoding happening in
non-DLL-exported functions defined in a dissector for #18478,
and removes unused functions and avoids duplicate decoding.
This also removes unnecessary early exit conditions for #18145.
Unit test cases for varint decoding are added to verify this.
This commit is contained in:
Brian Sipos 2022-10-16 17:30:19 -04:00 committed by AndersBroman
parent d2e5bd80cb
commit 5bb756e203
10 changed files with 274 additions and 490 deletions

View File

@ -56,8 +56,16 @@ static int dissect_admin_record(proto_tree *primary_tree, tvbuff_t *tvb, packet_
extern void
dissect_amp_as_subtree(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset);
static int evaluate_sdnv(tvbuff_t *tvb, int offset, int *bytecount);
/// Return an error_info index if not valid
static int evaluate_sdnv_ei(tvbuff_t *tvb, int offset, int *bytecount, expert_field **error);
static int add_sdnv_time_to_tree(proto_tree *tree, tvbuff_t *tvb, int offset, int hf_sdnv_time);
static gint64
evaluate_sdnv_64(tvbuff_t *tvb, int offset, int *bytecount);
static int proto_bundle = -1;
static dissector_handle_t bundle_handle = NULL;
@ -1834,48 +1842,24 @@ display_extension_block(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, int
}
/*3rd arg is number of bytes in field (returned)*/
int
static int
evaluate_sdnv(tvbuff_t *tvb, int offset, int *bytecount)
{
int value = 0;
guint8 curbyte;
guint64 value = 0;
*bytecount = tvb_get_varint(tvb, offset, FT_VARINT_MAX_LEN, &value, ENC_VARINT_SDNV);
*bytecount = 0;
if (!tvb_bytes_exist(tvb, offset, 1)) {
if (*bytecount == 0) {
return -1;
}
/*
* Get 1st byte and continue to get them while high-order bit is 1
*/
while ((curbyte = tvb_get_guint8(tvb, offset)) & ~SDNV_MASK) {
if (*bytecount >= (int) sizeof(int)) {
*bytecount = 0;
return -1;
}
value = value << 7;
value |= (curbyte & SDNV_MASK);
++offset;
++*bytecount;
if (!tvb_bytes_exist(tvb, offset, 1)) {
return -1;
}
if (value > G_MAXINT) {
ws_warning("evaluate_sdnv decoded a value too large to fit in an int, truncating");
return G_MAXINT;
}
/*
* Add in the byte whose high-order bit is 0 (last one)
*/
value = value << 7;
value |= (curbyte & SDNV_MASK);
++*bytecount;
return value;
return (int)value;
}
int evaluate_sdnv_ei(tvbuff_t *tvb, int offset, int *bytecount, expert_field **error) {
static int
evaluate_sdnv_ei(tvbuff_t *tvb, int offset, int *bytecount, expert_field **error) {
int value = evaluate_sdnv(tvb, offset, bytecount);
*error = (value < 0) ? &ei_bundle_sdnv_length : NULL;
return value;
@ -1883,199 +1867,18 @@ int evaluate_sdnv_ei(tvbuff_t *tvb, int offset, int *bytecount, expert_field **e
/* Special Function to evaluate 64 bit SDNVs */
/*3rd arg is number of bytes in field (returned)*/
gint64
static gint64
evaluate_sdnv_64(tvbuff_t *tvb, int offset, int *bytecount)
{
gint64 value = 0;
guint8 curbyte;
guint64 val = 0;
*bytecount = tvb_get_varint(tvb, offset, FT_VARINT_MAX_LEN, &val, ENC_VARINT_SDNV);
*bytecount = 0;
if (!tvb_bytes_exist(tvb, offset, 1)) {
if (*bytecount == 0) {
return -1;
}
/*
* Get 1st byte and continue to get them while high-order bit is 1
*/
while ((curbyte = tvb_get_guint8(tvb, offset)) & ~SDNV_MASK) {
if (*bytecount >= (int) sizeof(gint64)) {
*bytecount = 0;
return -1;
}
value = value << 7;
value |= (curbyte & SDNV_MASK);
++offset;
++*bytecount;
if (!tvb_bytes_exist(tvb, offset, 1)) {
return -1;
}
}
/*
* Add in the byte whose high-order bit is 0 (last one)
*/
value = value << 7;
value |= (curbyte & SDNV_MASK);
++*bytecount;
return value;
return val & G_MAXINT64;
}
/* Special Function to evaluate 32 bit unsigned SDNVs with error indication
* bytecount returns the number bytes consumed
* value returns the actual value
*
* result is TRUE (1) on success else FALSE (0)
*/
int
evaluate_sdnv32(tvbuff_t *tvb, int offset, int *bytecount, guint32 *value)
{
int result;
int num_bits_in_value;
guint8 curbyte;
guint8 high_bit;
*value = 0;
*bytecount = 0;
result = FALSE;
num_bits_in_value = 0;
if (tvb_bytes_exist(tvb, offset, 1)) {
/*
* Get 1st byte and continue to get them while high-order bit is 1
*/
result = TRUE;
/* Determine number of non-zero bits in first SDNV byte */
/* technically 0x80 0x80 ... 0x81 is a valid inefficient representation of "1" */
while ((0 == num_bits_in_value) && ((curbyte = tvb_get_guint8(tvb, offset)) & ~SDNV_MASK)) {
if (!tvb_bytes_exist(tvb, offset, 1)) {
result = FALSE;
break;
} else {
num_bits_in_value = 7;
high_bit = 0x40;
while ((num_bits_in_value > 0) && (!(curbyte & high_bit))) {
--num_bits_in_value;
high_bit = high_bit >> 1;
}
*value |= (curbyte & SDNV_MASK);
++offset;
++*bytecount;
}
}
/* Process additional bytes that have the high order bit set */
while (result && ((curbyte = tvb_get_guint8(tvb, offset)) & ~SDNV_MASK)) {
/* Since the high order bit is set there must be 7 low order bits after this byte */
if (!tvb_bytes_exist(tvb, offset, 1) || ((num_bits_in_value + 7) > (32 - 7))) {
result = FALSE;
} else {
*value = *value << 7;
*value |= (curbyte & SDNV_MASK);
++offset;
++*bytecount;
}
}
if (result) {
/*
* Add in the byte whose high-order bit is 0 (last one)
*/
*value = *value << 7;
*value |= (curbyte & SDNV_MASK);
++*bytecount;
} else {
*bytecount = 0;
}
}
return result;
}
/* Special Function to evaluate 64 bit unsigned SDNVs with error indication
* bytecount returns the number bytes consumed or zero on error
* value returns the actual value
*
* result is TRUE (1) on success else FALSE (0)
*/
int
evaluate_sdnv64(tvbuff_t *tvb, int offset, int *bytecount, guint64 *value)
{
int result;
int num_bits_in_value;
guint8 curbyte;
guint8 high_bit;
*value = 0;
*bytecount = 0;
result = FALSE;
num_bits_in_value = 0;
if (tvb_bytes_exist(tvb, offset, 1)) {
/*
* Get 1st byte and continue to get them while high-order bit is 1
*/
result = TRUE;
/* Determine number of non-zero bits in first SDNV byte */
/* technically 0x80 0x80 ... 0x81 is a valid inefficient representation of "1" */
while ((0 == num_bits_in_value) && ((curbyte = tvb_get_guint8(tvb, offset)) & ~SDNV_MASK)) {
if (!tvb_bytes_exist(tvb, offset, 1)) {
result = FALSE;
break;
} else {
num_bits_in_value = 7;
high_bit = 0x40;
while ((num_bits_in_value > 0) && (!(curbyte & high_bit))) {
--num_bits_in_value;
high_bit = high_bit >> 1;
}
*value |= (curbyte & SDNV_MASK);
++offset;
++*bytecount;
}
}
/* Process additional bytes that have the high order bit set */
while (result && ((curbyte = tvb_get_guint8(tvb, offset)) & ~SDNV_MASK)) {
/* Since the high order bit is set there must be 7 low order bits after this byte */
if (!tvb_bytes_exist(tvb, offset, 1) || ((num_bits_in_value + 7) > (64 - 7))) {
result = FALSE;
} else {
*value = *value << 7;
*value |= (curbyte & SDNV_MASK);
++offset;
++*bytecount;
}
}
if (result) {
/*
* Add in the byte whose high-order bit is 0 (last one)
*/
*value = *value << 7;
*value |= (curbyte & SDNV_MASK);
++*bytecount;
} else {
*bytecount = 0;
}
}
return result;
}
static int
dissect_bpv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
{

View File

@ -112,33 +112,6 @@ extern "C" {
#define DTN_SCHEME_STR "dtn"
#define IPN_SCHEME_STR "ipn"
/*
* SDNV has a zero in high-order bit position of last byte. The high-order
* bit of all preceding bytes is set to one. This returns the numeric value
* in an integer and sets the value of the second argument to the number of
* bytes used to code the SDNV. A -1 is returned if the evaluation fails
* (value exceeds maximum for signed integer). 0 is an acceptable value.
*/
#define SDNV_MASK 0x7f
int evaluate_sdnv(tvbuff_t *tvb, int offset, int *bytecount);
/// Return an error_info index if not valid
int evaluate_sdnv_ei(tvbuff_t *tvb, int offset, int *bytecount, expert_field **error);
gint64 evaluate_sdnv_64(tvbuff_t *tvb, int offset, int *bytecount);
/* Special Functions to evaluate unsigned SDNVs with error indication
* bytecount returns the number bytes consumed
* value returns the actual value
*
* result is TRUE (1) on success else FALSE (0)
*/
int evaluate_sdnv32(tvbuff_t *tvb, int offset, int *bytecount, guint32 *value);
int evaluate_sdnv64(tvbuff_t *tvb, int offset, int *bytecount, guint64 *value);
#ifdef __cplusplus
}
#endif

View File

@ -44,14 +44,10 @@
#include <wsutil/wmem/wmem_map.h>
#include <wsutil/wmem/wmem_interval_tree.h>
#include "packet-bpv6.h"
void proto_register_ltp(void);
void proto_reg_handoff_ltp(void);
#define LTP_MIN_DATA_BUFFER 5
#define LTP_MAX_HDR_EXTN 16
#define LTP_MAX_TRL_EXTN 16
/// Unique session identifier
typedef struct {
@ -333,7 +329,6 @@ static int hf_ltp_fragment_count = -1;
static int hf_ltp_reassembled_in = -1;
static int hf_ltp_reassembled_length = -1;
static expert_field ei_ltp_neg_reception_claim_count = EI_INIT;
static expert_field ei_ltp_mal_reception_claim = EI_INIT;
static expert_field ei_ltp_sdnv_length = EI_INIT;
static expert_field ei_ltp_sno_larger_than_ccsds = EI_INIT;
@ -445,24 +440,16 @@ static const fragment_items ltp_frag_items = {
"LTP fragments"
};
static int
add_sdnv64_to_tree(proto_tree *tree, tvbuff_t *tvb, packet_info* pinfo, int offset, int hf_sdnv, guint64 *value, proto_item** item_ret)
static proto_item *
add_sdnv64_to_tree(proto_tree *tree, tvbuff_t *tvb, packet_info* pinfo, int offset, int hf_sdnv, guint64 *retval, gint *lenretval)
{
int sdnv_status;
int sdnv_length;
guint64 sdnv_value;
proto_item* ti;
proto_item *ti;
ti = proto_tree_add_item_ret_varint(tree, hf_sdnv, tvb, offset, -1, ENC_VARINT_SDNV, retval, lenretval);
sdnv_status = evaluate_sdnv64(tvb, offset, &sdnv_length, &sdnv_value);
ti = proto_tree_add_uint64(tree, hf_sdnv, tvb, offset, sdnv_length, sdnv_value);
*value = sdnv_value;
if (NULL != *item_ret) *item_ret = ti;
if (!sdnv_status) {
if (*lenretval <= 0) {
expert_add_info(pinfo, ti, &ei_ltp_sdnv_length);
}
return sdnv_length;
return ti;
}
/// Summary of a data segment tree item
@ -519,7 +506,6 @@ dissect_data_segment(proto_tree *ltp_tree, tvbuff_t *tvb,packet_info *pinfo,int
unsigned segment_size = 0;
int sdnv_length;
int sdnv_status;
proto_tree *ltp_data_tree;
proto_item *ti;
@ -531,22 +517,14 @@ dissect_data_segment(proto_tree *ltp_tree, tvbuff_t *tvb,packet_info *pinfo,int
/* Create a subtree for data segment and add the other fields under it */
ltp_data_tree = proto_tree_add_subtree(ltp_tree, tvb, frame_offset, tvb_captured_length_remaining(tvb, frame_offset), ett_data_segm, NULL, "Data Segment");
/* Client ID - 0 = Bundle Protocol, 1 = CCSDS LTP Service Data Aggregation */
sdnv_status = evaluate_sdnv64(tvb, frame_offset, &sdnv_length, &client_id);
ti = proto_tree_add_uint64_format_value(ltp_data_tree, hf_ltp_data_clid, tvb, frame_offset, sdnv_length, client_id,
"%" PRIu64 " (%s)", client_id,
val64_to_str_const(client_id, client_service_id_info, "Invalid"));
if (!sdnv_status) {
expert_add_info(pinfo, ti, &ei_ltp_sdnv_length);
return 0;
}
add_sdnv64_to_tree(ltp_data_tree, tvb, pinfo, frame_offset, hf_ltp_data_clid, &client_id, &sdnv_length);
frame_offset += sdnv_length;
segment_size += sdnv_length;
/* data segment offset */
if ((sdnv_length = add_sdnv64_to_tree(ltp_data_tree, tvb, pinfo, frame_offset, hf_ltp_data_offset, &data_offset, &ti)) > 0) {
add_sdnv64_to_tree(ltp_data_tree, tvb, pinfo, frame_offset, hf_ltp_data_offset, &data_offset, &sdnv_length);
if (sdnv_length > 0) {
frame_offset += sdnv_length;
segment_size += sdnv_length;
} else {
@ -554,7 +532,8 @@ dissect_data_segment(proto_tree *ltp_tree, tvbuff_t *tvb,packet_info *pinfo,int
}
/* data segment length */
if ((sdnv_length = add_sdnv64_to_tree(ltp_data_tree, tvb, pinfo, frame_offset, hf_ltp_data_length, &data_length, &ti)) > 0) {
add_sdnv64_to_tree(ltp_data_tree, tvb, pinfo, frame_offset, hf_ltp_data_length, &data_length, &sdnv_length);
if (sdnv_length > 0) {
frame_offset += sdnv_length;
segment_size += sdnv_length;
@ -607,7 +586,8 @@ dissect_data_segment(proto_tree *ltp_tree, tvbuff_t *tvb,packet_info *pinfo,int
if (ltp_type != 0 && ltp_type < 4)
{
/* checkpoint serial number - 32 bits per CCSDS */
if ((sdnv_length = add_sdnv64_to_tree(ltp_data_tree, tvb, pinfo, frame_offset, hf_ltp_data_chkp, &chkp_sno, &ti)) > 0) {
ti = add_sdnv64_to_tree(ltp_data_tree, tvb, pinfo, frame_offset, hf_ltp_data_chkp, &chkp_sno, &sdnv_length);
if (sdnv_length > 0) {
frame_offset += sdnv_length;
segment_size += sdnv_length;
@ -626,7 +606,8 @@ dissect_data_segment(proto_tree *ltp_tree, tvbuff_t *tvb,packet_info *pinfo,int
}
/* report serial number - 32 bits per CCSDS */
if ((sdnv_length = add_sdnv64_to_tree(ltp_data_tree, tvb, pinfo, frame_offset, hf_ltp_data_rpt, &rpt_sno, &ti)) > 0) {
ti = add_sdnv64_to_tree(ltp_data_tree, tvb, pinfo, frame_offset, hf_ltp_data_rpt, &rpt_sno, &sdnv_length);
if (sdnv_length > 0) {
frame_offset += sdnv_length;
segment_size += sdnv_length;
@ -734,15 +715,7 @@ dissect_data_segment(proto_tree *ltp_tree, tvbuff_t *tvb,packet_info *pinfo,int
tvbuff_t *datatvb;
if (client_id == 2) {
sdnv_status = evaluate_sdnv64(new_tvb, parse_offset, &sdnv_length, &sda_client_id);
ti = proto_tree_add_uint64_format_value(root_tree, hf_ltp_data_sda_clid, new_tvb, parse_offset, sdnv_length, sda_client_id,
"%" G_GINT64_MODIFIER "u (%s)", sda_client_id, val64_to_str_const(sda_client_id, client_service_id_info, "Invalid"));
if (!sdnv_status) {
expert_add_info(pinfo, ti, &ei_ltp_sdnv_length);
return 0;
}
add_sdnv64_to_tree(ltp_data_tree, tvb, pinfo, frame_offset+parse_offset, hf_ltp_data_sda_clid, &sda_client_id, &sdnv_length);
parse_offset += sdnv_length;
if (parse_offset == parse_length) {
col_set_str(pinfo->cinfo, COL_INFO, "CCSDS LTP SDA Protocol Error");
@ -831,7 +804,7 @@ dissect_report_segment(tvbuff_t *tvb, packet_info *pinfo, proto_tree *ltp_tree,
gint64 chkp_sno;
guint64 upper_bound;
guint64 lower_bound;
int rcpt_clm_cnt;
guint64 rcpt_clm_cnt;
guint64 offset;
guint64 length;
guint64 clm_fst, clm_lst;
@ -847,9 +820,9 @@ dissect_report_segment(tvbuff_t *tvb, packet_info *pinfo, proto_tree *ltp_tree,
int segment_offset = 0;
int gap_count = 0;
guint64 gap_total = 0;
int i;
proto_item *ltp_rpt_item;
proto_item *ltp_rpt_clm_cnt;
proto_item *ltp_rpt_clm_item;
proto_item *item_rpt_sno, *item_chkp_sno;
@ -860,8 +833,7 @@ dissect_report_segment(tvbuff_t *tvb, packet_info *pinfo, proto_tree *ltp_tree,
ltp_rpt_tree = proto_tree_add_subtree(ltp_tree, tvb, frame_offset, -1, ett_rpt_segm, &ltp_rpt_item, "Report Segment");
/* Extract the report segment info */
rpt_sno = evaluate_sdnv_64(tvb, frame_offset, &rpt_sno_size);
item_rpt_sno = proto_tree_add_uint64(ltp_rpt_tree, hf_ltp_rpt_sno, tvb, frame_offset + segment_offset, rpt_sno_size, (guint64)rpt_sno);
item_rpt_sno = add_sdnv64_to_tree(ltp_rpt_tree, tvb, pinfo, frame_offset + segment_offset, hf_ltp_rpt_sno, &rpt_sno, &rpt_sno_size);
segment_offset += rpt_sno_size;
if (ltp_analyze_sequence && session)
{
@ -871,8 +843,7 @@ dissect_report_segment(tvbuff_t *tvb, packet_info *pinfo, proto_tree *ltp_tree,
ltp_ref_use(session->rpt_datas, rpt_sno, pinfo, tree_rpt_sno, hf_ltp_rpt_sno_data, -1);
}
chkp_sno = evaluate_sdnv_64(tvb, frame_offset + segment_offset, &chkp_sno_size);
item_chkp_sno = proto_tree_add_uint64(ltp_rpt_tree, hf_ltp_rpt_chkp, tvb, frame_offset + segment_offset, chkp_sno_size, (guint64)chkp_sno);
item_chkp_sno = add_sdnv64_to_tree(ltp_rpt_tree, tvb, pinfo, frame_offset + segment_offset, hf_ltp_rpt_chkp, &chkp_sno, &chkp_sno_size);
segment_offset += chkp_sno_size;
if (ltp_analyze_sequence && session)
{
@ -886,12 +857,10 @@ dissect_report_segment(tvbuff_t *tvb, packet_info *pinfo, proto_tree *ltp_tree,
}
}
upper_bound = evaluate_sdnv(tvb, frame_offset + segment_offset, &upper_bound_size);
proto_tree_add_uint64(ltp_rpt_tree, hf_ltp_rpt_ub, tvb, frame_offset + segment_offset, upper_bound_size, upper_bound);
add_sdnv64_to_tree(ltp_rpt_tree, tvb, pinfo, frame_offset + segment_offset, hf_ltp_rpt_ub, &upper_bound, &upper_bound_size);
segment_offset += upper_bound_size;
lower_bound = evaluate_sdnv(tvb, frame_offset + segment_offset, &lower_bound_size);
proto_tree_add_uint64(ltp_rpt_tree, hf_ltp_rpt_lb, tvb, frame_offset + segment_offset, lower_bound_size, lower_bound);
add_sdnv64_to_tree(ltp_rpt_tree, tvb, pinfo, frame_offset + segment_offset, hf_ltp_rpt_lb, &lower_bound, &lower_bound_size);
segment_offset += lower_bound_size;
PROTO_ITEM_SET_GENERATED(
@ -942,42 +911,34 @@ dissect_report_segment(tvbuff_t *tvb, packet_info *pinfo, proto_tree *ltp_tree,
}
tap->corr_orig = newdata;
rcpt_clm_cnt = evaluate_sdnv(tvb, frame_offset + segment_offset, &rcpt_clm_cnt_size);
if (rcpt_clm_cnt < 0){
proto_item_set_end(ltp_rpt_item, tvb, frame_offset + segment_offset);
expert_add_info_format(pinfo, ltp_tree, &ei_ltp_neg_reception_claim_count,
"Negative reception claim count: %d", rcpt_clm_cnt);
return 0;
}
ltp_rpt_clm_cnt = add_sdnv64_to_tree(ltp_rpt_tree, tvb, pinfo, frame_offset + segment_offset, hf_ltp_rpt_clm_cnt, &rcpt_clm_cnt, &rcpt_clm_cnt_size);
segment_offset += rcpt_clm_cnt_size;
/* Each reception claim is at least 2 bytes, so if the count is larger than the
* max number of claims we can possibly squeeze into the remaining tvbuff, then
* the packet is malformed.
*/
if (rcpt_clm_cnt > tvb_captured_length_remaining(tvb, frame_offset + segment_offset) / 2) {
proto_item_set_end(ltp_rpt_item, tvb, frame_offset + segment_offset);
expert_add_info_format(pinfo, ltp_tree, &ei_ltp_mal_reception_claim,
"Reception claim count impossibly large: %d > %d", rcpt_clm_cnt,
if (rcpt_clm_cnt > (guint64)tvb_captured_length_remaining(tvb, frame_offset + segment_offset) / 2) {
expert_add_info_format(pinfo, ltp_rpt_clm_cnt, &ei_ltp_mal_reception_claim,
"Reception claim count impossibly large: %" G_GINT64_MODIFIER "d > %d", rcpt_clm_cnt,
tvb_captured_length_remaining(tvb, frame_offset + segment_offset) / 2);
return 0;
}
proto_tree_add_uint(ltp_rpt_tree, hf_ltp_rpt_clm_cnt, tvb, frame_offset + segment_offset, rcpt_clm_cnt_size, rcpt_clm_cnt);
segment_offset += rcpt_clm_cnt_size;
clm_lst = lower_bound - 1;
/* There can be multiple reception claims in the same report segment */
for(i = 0; i<rcpt_clm_cnt; i++){
offset = evaluate_sdnv(tvb,frame_offset + segment_offset, &offset_size);
for(guint64 ix = 0; ix < rcpt_clm_cnt; ix++){
/* Peek at the offset to see if there is a preceeding gap */
tvb_get_varint(tvb, frame_offset + segment_offset, FT_VARINT_MAX_LEN, &offset, ENC_VARINT_SDNV);
clm_fst = lower_bound + offset;
ltp_check_reception_gap(ltp_rpt_tree, pinfo, session, clm_lst, clm_fst, &gap_count, &gap_total);
ltp_rpt_clm_tree = proto_tree_add_subtree(ltp_rpt_tree, tvb, frame_offset + segment_offset, -1, ett_rpt_clm, &ltp_rpt_clm_item, "Reception claim");
proto_tree_add_uint64(ltp_rpt_clm_tree, hf_ltp_rpt_clm_off, tvb, frame_offset + segment_offset, offset_size, offset);
add_sdnv64_to_tree(ltp_rpt_clm_tree, tvb, pinfo, frame_offset + segment_offset, hf_ltp_rpt_clm_off, &offset, &offset_size);
segment_offset += offset_size;
length = evaluate_sdnv(tvb,frame_offset + segment_offset, &length_size);
proto_tree_add_uint64(ltp_rpt_clm_tree, hf_ltp_rpt_clm_len, tvb, frame_offset + segment_offset, length_size, length);
add_sdnv64_to_tree(ltp_rpt_clm_tree, tvb, pinfo, frame_offset + segment_offset, hf_ltp_rpt_clm_len, &length, &length_size);
segment_offset += length_size;
PROTO_ITEM_SET_GENERATED(
@ -1030,23 +991,18 @@ dissect_report_ack_segment(proto_tree *ltp_tree, tvbuff_t *tvb, packet_info *pin
int rpt_sno_size;
int segment_offset = 0;
proto_item *item_rpt_sno;
proto_item *ltp_rpt_ack_item, *item_rpt_sno;
proto_tree *ltp_rpt_ack_tree;
/* Creating tree for the report ack segment */
ltp_rpt_ack_tree = proto_tree_add_subtree(ltp_tree, tvb,frame_offset, -1,
ett_rpt_ack_segm, &ltp_rpt_ack_item, "Report Ack Segment");
/* Extracing receipt serial number info */
rpt_sno = evaluate_sdnv_64(tvb,frame_offset, &rpt_sno_size);
/* XXX - verify that this does not overflow */
item_rpt_sno = add_sdnv64_to_tree(ltp_rpt_ack_tree, tvb, pinfo, frame_offset + segment_offset, hf_ltp_rpt_ack_sno, &rpt_sno, &rpt_sno_size);
segment_offset += rpt_sno_size;
if((unsigned)(frame_offset + segment_offset) > tvb_captured_length(tvb)){
return 0;
}
/* Creating tree for the report ack segment */
ltp_rpt_ack_tree = proto_tree_add_subtree(ltp_tree, tvb,frame_offset, segment_offset,
ett_rpt_ack_segm, NULL, "Report Ack Segment");
item_rpt_sno = proto_tree_add_uint64(ltp_rpt_ack_tree, hf_ltp_rpt_ack_sno, tvb, frame_offset,rpt_sno_size, (guint64)rpt_sno);
proto_item_set_end(ltp_rpt_ack_item, tvb, frame_offset + segment_offset);
if (ltp_analyze_sequence && session)
{
@ -1079,97 +1035,60 @@ dissect_cancel_segment(proto_tree * ltp_tree, tvbuff_t *tvb, int frame_offset, l
static int
dissect_header_extn(proto_tree *ltp_tree, tvbuff_t *tvb,int frame_offset,int hdr_extn_cnt){
guint8 extn_type[LTP_MAX_HDR_EXTN];
gint64 length[LTP_MAX_HDR_EXTN];
dissect_header_extn(proto_tree *ltp_tree, tvbuff_t *tvb, packet_info *pinfo, int frame_offset,int hdr_extn_cnt){
gint64 length;
int length_size;
int length_size[LTP_MAX_HDR_EXTN];
int i;
int extn_offset = 0;
proto_item *ltp_hdr_extn_item;
proto_tree *ltp_hdr_extn_tree;
/* There can be more than one header extensions */
for(i = 0; i < hdr_extn_cnt; i++){
extn_type[i] = tvb_get_guint8(tvb,frame_offset);
extn_offset++;
ltp_hdr_extn_tree = proto_tree_add_subtree(ltp_tree, tvb,frame_offset, -1, ett_hdr_extn, &ltp_hdr_extn_item, "Header Extension");
length[i] = evaluate_sdnv_64(tvb,frame_offset+1,&length_size[i]);
if((guint64)(frame_offset + extn_offset + length_size[i] + length[i]) >= (guint64)tvb_captured_length(tvb)){
return 0;
}
extn_offset += length_size[i];
for(int ix = 0; ix < hdr_extn_cnt; ix++){
/* From RFC-5326, the total length of the Header Extension Tree will be length of the following:
a) Extension type length (1 byte)
b) The length of the 'length' field (as defined by the SDNV which handles dynamic size)
c) The length of the value field which is the decoded length */
extn_offset += (int)length[i];
proto_tree_add_item(ltp_hdr_extn_tree, hf_ltp_hdr_extn_tag, tvb, frame_offset + extn_offset, 1, ENC_NA);
extn_offset += 1;
add_sdnv64_to_tree(ltp_hdr_extn_tree, tvb, pinfo, frame_offset + extn_offset, hf_ltp_hdr_extn_len, &length, &length_size);
extn_offset += length_size;
proto_tree_add_item(ltp_hdr_extn_tree, hf_ltp_hdr_extn_val, tvb, frame_offset + extn_offset, (int)length, ENC_NA);
extn_offset += (int)length;
}
ltp_hdr_extn_tree = proto_tree_add_subtree(ltp_tree, tvb,frame_offset, extn_offset, ett_hdr_extn, NULL, "Header Extension");
for(i = 0; i < hdr_extn_cnt; i++){
proto_tree_add_uint_format_value(ltp_hdr_extn_tree, hf_ltp_hdr_extn_tag, tvb, frame_offset, 1, extn_type[i], "%x (%s)", extn_type[i], val_to_str_const(extn_type[i],extn_tag_codes,"Unassigned/Reserved"));
frame_offset += 1;
proto_tree_add_uint64_format(ltp_hdr_extn_tree, hf_ltp_hdr_extn_len, tvb, frame_offset, length_size[i],length[i], "Length [%d]: %"PRId64,i+1,length[i]);
frame_offset += length_size[i];
proto_tree_add_item (ltp_hdr_extn_tree, hf_ltp_hdr_extn_val, tvb, frame_offset, (int)length[i], ENC_NA);
frame_offset += (int)length[i];
}
proto_item_set_end(ltp_hdr_extn_item, tvb, frame_offset + extn_offset);
return extn_offset;
}
static int
dissect_trailer_extn(proto_tree *ltp_tree, tvbuff_t *tvb,int frame_offset,int trl_extn_cnt){
guint8 extn_type[LTP_MAX_TRL_EXTN];
gint64 length[LTP_MAX_TRL_EXTN];
dissect_trailer_extn(proto_tree *ltp_tree, tvbuff_t *tvb, packet_info *pinfo, int frame_offset,int trl_extn_cnt){
gint64 length;
int length_size;
int length_size[LTP_MAX_TRL_EXTN];
int i;
int extn_offset = 0;
proto_item *ltp_trl_extn_item;
proto_tree *ltp_trl_extn_tree;
DISSECTOR_ASSERT(trl_extn_cnt < LTP_MAX_TRL_EXTN);
ltp_trl_extn_tree = proto_tree_add_subtree(ltp_tree, tvb,frame_offset, -1, ett_trl_extn, &ltp_trl_extn_item, "Trailer Extension");
for(i = 0; i < trl_extn_cnt; i++){
extn_type[i] = tvb_get_guint8(tvb,frame_offset);
extn_offset++;
if((unsigned)(frame_offset + extn_offset) >= tvb_captured_length(tvb)){
return 0;
}
length[i] = evaluate_sdnv_64(tvb,frame_offset+1,&length_size[i]);
extn_offset += length_size[i];
if((guint64)(frame_offset + extn_offset + length_size[i] + length[i]) >= tvb_captured_length(tvb)){
return 0;
}
/* From RFC-5326, the total length of the Trailer Extension Tree will be length of the following:
a) Extension type length (1 byte)
b) The length of the 'length' field (as defined by the SDNV which handles dynamic size)
c) The length of the value field which is the decoded length */
extn_offset += (int)length[i];
}
ltp_trl_extn_tree = proto_tree_add_subtree(ltp_tree, tvb,frame_offset, extn_offset, ett_trl_extn, NULL, "Trailer Extension");
for(i = 0; i < trl_extn_cnt; i++){
proto_tree_add_uint_format_value(ltp_trl_extn_tree, hf_ltp_trl_extn_tag, tvb, frame_offset, 1, extn_type[i], "%x (%s)", extn_type[i], val_to_str_const(extn_type[i],extn_tag_codes,"Unassigned/Reserved"));
for(int ix = 0; ix < trl_extn_cnt; ix++){
proto_tree_add_item(ltp_trl_extn_tree, hf_ltp_trl_extn_tag, tvb, frame_offset + extn_offset, 1, ENC_NA);
frame_offset += 1;
proto_tree_add_uint64_format(ltp_trl_extn_tree, hf_ltp_trl_extn_len, tvb, frame_offset, length_size[i], length[i], "Length [%d]: %"PRId64,i+1,length[i]);
frame_offset += length_size[i];
add_sdnv64_to_tree(ltp_trl_extn_tree, tvb, pinfo, frame_offset + extn_offset, hf_ltp_hdr_extn_len, &length, &length_size);
frame_offset += length_size;
proto_tree_add_item (ltp_trl_extn_tree, hf_ltp_trl_extn_val, tvb, frame_offset, (int)length[i], ENC_NA);
frame_offset += (int)length[i];
proto_tree_add_item(ltp_trl_extn_tree, hf_ltp_trl_extn_val, tvb, frame_offset + extn_offset, (int)length, ENC_NA);
frame_offset += (int)length;
}
proto_item_set_end(ltp_trl_extn_item, tvb, frame_offset + extn_offset);
return extn_offset;
}
@ -1224,21 +1143,11 @@ dissect_ltp_segment(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *t
ltp_session_tree = proto_tree_add_subtree(ltp_header_tree, tvb, frame_offset, 0, ett_hdr_session, NULL, "Session ID");
ltp_session_item = proto_tree_get_parent(ltp_session_tree);
sess_id.orig_eng_id = evaluate_sdnv_64(tvb,frame_offset,&engine_id_size);
proto_tree_add_uint64(ltp_session_tree,hf_ltp_session_orig,tvb,frame_offset,engine_id_size,sess_id.orig_eng_id);
add_sdnv64_to_tree(ltp_session_tree, tvb, pinfo, frame_offset, hf_ltp_session_orig, &sess_id.orig_eng_id, &engine_id_size);
frame_offset += engine_id_size;
if((unsigned)frame_offset >= tvb_captured_length(tvb)){
col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error");
return 0;
}
sess_id.sess_num = evaluate_sdnv_64(tvb,frame_offset,&session_num_size);
proto_tree_add_uint64(ltp_session_tree,hf_ltp_session_no, tvb, frame_offset,session_num_size,sess_id.sess_num);
add_sdnv64_to_tree(ltp_session_tree, tvb, pinfo, frame_offset, hf_ltp_session_no, &sess_id.sess_num, &session_num_size);
frame_offset += session_num_size;
if((unsigned)frame_offset >= tvb_captured_length(tvb)){
col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error");
return 0;
}
proto_item_set_end(ltp_session_item, tvb, frame_offset);
tap->sess_id = sess_id;
@ -1303,33 +1212,12 @@ dissect_ltp_segment(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *t
col_add_fstr(pinfo->cinfo, COL_INFO, "Session %s, %s", sess_name, val_to_str_const(ltp_type,ltp_type_col_info,"Protocol Error"));
/* Check if there are any header extensions */
if(hdr_extn_cnt > 0){
int hdr_extn_offset;
if((unsigned)frame_offset >= tvb_captured_length(tvb)){
col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error");
return 0;
}
hdr_extn_offset = dissect_header_extn(ltp_tree, tvb, frame_offset,hdr_extn_cnt);
if(hdr_extn_offset == 0){
col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error");
return 0;
}
if(hdr_extn_cnt > 0)
{
int hdr_extn_offset = dissect_header_extn(ltp_tree, tvb, pinfo, frame_offset,hdr_extn_cnt);
frame_offset += hdr_extn_offset;
}
if((unsigned)frame_offset > tvb_captured_length(tvb)){
col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error");
return 0;
}
else if((unsigned)frame_offset == tvb_captured_length(tvb)){
if(ltp_type != 13 && ltp_type != 15){
col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error");
return 0;
}
}
/* Call sub routines to handle the segment content*/
if((ltp_type >= 0) && (ltp_type < 8)){
segment_offset = dissect_data_segment(ltp_tree,tvb,pinfo,frame_offset,ltp_type, &data_len, tap);
@ -1366,17 +1254,9 @@ dissect_ltp_segment(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *t
/* Check to see if there are any trailer extensions */
const int trl_start = frame_offset;
int trl_length = 0;
if(trl_extn_cnt > 0){
if((unsigned)frame_offset >= tvb_captured_length(tvb)){
col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error");
return 0;
}
trl_length = dissect_trailer_extn(ltp_tree, tvb, frame_offset,trl_extn_cnt);
if(0 == trl_length) {
col_set_str(pinfo->cinfo, COL_INFO, "Protocol Error");
return 0;
}
if(trl_extn_cnt > 0)
{
int trl_length = dissect_trailer_extn(ltp_tree, tvb, pinfo, frame_offset,trl_extn_cnt);
frame_offset += trl_length;
}
@ -1717,7 +1597,7 @@ proto_register_ltp(void)
},
{&hf_ltp_data_clid,
{"Client service ID","ltp.data.client.id",
FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
FT_UINT64,BASE_DEC | BASE_VAL64_STRING, VALS64(client_service_id_info), 0x0, NULL, HFILL}
},
{&hf_ltp_data_offset,
{"Offset","ltp.data.offset",
@ -1818,7 +1698,7 @@ proto_register_ltp(void)
},
{&hf_ltp_rpt_clm_cnt,
{"Reception claim count","ltp.rpt.clm.cnt",
FT_UINT8,BASE_DEC,NULL, 0x0, NULL, HFILL}
FT_UINT64,BASE_DEC,NULL, 0x0, NULL, HFILL}
},
{&hf_ltp_rpt_clm_off,
{"Offset","ltp.rpt.clm.off",
@ -1876,7 +1756,7 @@ proto_register_ltp(void)
},
{&hf_ltp_hdr_extn_tag,
{"Extension tag","ltp.hdr.extn.tag",
FT_UINT8,BASE_HEX,NULL, 0x0, NULL, HFILL}
FT_UINT8,BASE_HEX,VALS(extn_tag_codes), 0x0, NULL, HFILL}
},
{&hf_ltp_hdr_extn_len,
{"Length","ltp.hdr.extn.len",
@ -1888,7 +1768,7 @@ proto_register_ltp(void)
},
{&hf_ltp_trl_extn_tag,
{"Extension tag","ltp.trl.extn.tag",
FT_UINT8,BASE_HEX,NULL, 0x0, NULL, HFILL}
FT_UINT8,BASE_HEX,VALS(extn_tag_codes), 0x0, NULL, HFILL}
},
{&hf_ltp_trl_extn_len,
{"Length","ltp.trl.extn.len",
@ -1973,7 +1853,6 @@ proto_register_ltp(void)
};
static ei_register_info ei[] = {
{ &ei_ltp_neg_reception_claim_count, { "ltp.neg_reception_claim_count", PI_UNDECODED, PI_ERROR, "Negative reception claim count", EXPFILL }},
{ &ei_ltp_mal_reception_claim, { "ltp.mal_reception_claim", PI_MALFORMED, PI_ERROR, "Reception claim count impossibly large", EXPFILL }},
{ &ei_ltp_sdnv_length, { "ltp.sdnv_length_invalid", PI_PROTOCOL, PI_ERROR, "SDNV length error", EXPFILL }},
{ &ei_ltp_sno_larger_than_ccsds, { "ltp.serial_number_too_large", PI_PROTOCOL, PI_WARN, "Serial number larger than CCSDS specification", EXPFILL }},

View File

@ -282,7 +282,7 @@ static hf_register_info hf_tcpcl[] = {
{&hf_tcpclv3_xfer_id, {"Implied Transfer ID", "tcpcl.xfer_id", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL}},
{&hf_tcpclv3_data_segment_length,
{"Segment Length", "tcpcl.data.length",
FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL}
FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL}
},
{&hf_tcpclv3_data_segment_data,
{"Segment Data", "tcpcl.data",
@ -310,7 +310,7 @@ static hf_register_info hf_tcpcl[] = {
},
{&hf_tcpclv3_ack_length,
{"Ack Length", "tcpcl.ack.length",
FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL}
FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL}
},
{&hf_tcpclv3_chdr_flags,
{"Flags", "tcpcl.contact_hdr.flags",
@ -338,7 +338,7 @@ static hf_register_info hf_tcpcl[] = {
},
{&hf_tcpclv3_chdr_local_eid_length,
{"Local EID Length", "tcpcl.contact_hdr.local_eid_length",
FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL}
FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL}
},
{&hf_tcpclv4_chdr_flags, {"Contact Flags", "tcpcl.v4.chdr.flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}},
@ -532,6 +532,7 @@ static expert_field ei_invalid_version = EI_INIT;
static expert_field ei_mismatch_version = EI_INIT;
static expert_field ei_chdr_duplicate = EI_INIT;
static expert_field ei_tcpclv3_eid_length = EI_INIT;
static expert_field ei_tcpclv3_invalid_msg_type = EI_INIT;
static expert_field ei_tcpclv3_data_flags = EI_INIT;
static expert_field ei_tcpclv3_segment_length = EI_INIT;
@ -564,6 +565,7 @@ static ei_register_info ei_tcpcl[] = {
{&ei_mismatch_version, { "tcpcl.mismatch_contact_version", PI_PROTOCOL, PI_ERROR, "Protocol version mismatch", EXPFILL}},
{&ei_chdr_duplicate, { "tcpcl.contact_duplicate", PI_SEQUENCE, PI_ERROR, "Duplicate Contact Header", EXPFILL}},
{&ei_tcpclv3_eid_length, { "tcpcl.eid_length_invalid", PI_PROTOCOL, PI_ERROR, "Invalid EID Length", EXPFILL }},
{&ei_tcpclv3_invalid_msg_type, { "tcpcl.unknown_message_type", PI_UNDECODED, PI_ERROR, "Message type is unknown", EXPFILL}},
{&ei_tcpclv3_data_flags, { "tcpcl.data.flags.invalid", PI_PROTOCOL, PI_WARN, "Invalid TCP CL Data Segment Flags", EXPFILL }},
{&ei_tcpclv3_segment_length, { "tcpcl.data.length.invalid", PI_PROTOCOL, PI_ERROR, "Invalid Data Length", EXPFILL }},
@ -614,6 +616,10 @@ static const fragment_items xfer_frag_items = {
"Transfer fragments"
};
static guint tvb_get_sdnv(tvbuff_t *tvb, guint offset, guint64 *value) {
return tvb_get_varint(tvb, offset, FT_VARINT_MAX_LEN, value, ENC_VARINT_SDNV);
}
static void tcpcl_frame_loc_init(tcpcl_frame_loc_t *loc, const packet_info *pinfo, tvbuff_t *tvb, const gint offset) {
loc->frame_num = pinfo->num;
// This is a messy way to determine the index,
@ -1164,7 +1170,8 @@ get_v3_msg_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset,
tcpcl_dissect_ctx_t *ctx _U_)
{
const int orig_offset = offset;
int len, bytecount;
guint64 len;
guint bytecount;
guint8 conv_hdr = tvb_get_guint8(tvb, offset);
offset += 1;
@ -1172,8 +1179,8 @@ get_v3_msg_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset,
{
case TCPCLV3_DATA_SEGMENT:
/* get length from sdnv */
len = evaluate_sdnv(tvb, offset, &bytecount);
if (len < 0)
bytecount = tvb_get_sdnv(tvb, offset, &len);
if (bytecount == 0)
return 0;
offset += bytecount+len;
@ -1181,8 +1188,8 @@ get_v3_msg_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset,
case TCPCLV3_ACK_SEGMENT:
/* get length from sdnv */
len = evaluate_sdnv(tvb, offset, &bytecount);
if (len < 0)
bytecount = tvb_get_sdnv(tvb, offset, &len);
if (bytecount == 0)
return 0;
offset += bytecount;
@ -1203,8 +1210,8 @@ get_v3_msg_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset,
case TCPCLV3_LENGTH:
/* get length from sdnv */
len = evaluate_sdnv(tvb, offset, &bytecount);
if (len < 0)
bytecount = tvb_get_sdnv(tvb, offset, &len);
if (bytecount == 0)
return 0;
offset += bytecount;
break;
@ -1222,7 +1229,8 @@ dissect_v3_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
const char *msgtype_name;
guint8 refuse_bundle_hdr;
int offset = 0;
int sdnv_length, segment_length;
gint sdnv_length;
guint64 segment_length;
proto_item *conv_item, *sub_item;
proto_tree *conv_tree, *sub_tree;
guint64 *xfer_id = NULL;
@ -1248,19 +1256,20 @@ dissect_v3_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
ett_tcpclv3_data_procflags, v3_data_procflags,
ENC_BIG_ENDIAN
);
offset += 1;
/* Only Start and End flags (bits 0 & 1) are valid in Data Segment */
if ((conv_hdr & ~(TCPCLV3_TYPE_MASK | TCPCLV3_DATA_FLAGS)) != 0) {
expert_add_info(pinfo, item_flags, &ei_tcpclv3_data_flags);
}
segment_length = evaluate_sdnv(tvb, 1, &sdnv_length);
sub_item = proto_tree_add_int(conv_tree, hf_tcpclv3_data_segment_length, tvb, 1, sdnv_length, segment_length);
if (segment_length < 0) {
sub_item = proto_tree_add_item_ret_varint(conv_tree, hf_tcpclv3_data_segment_length, tvb, offset, -1, ENC_VARINT_SDNV, &segment_length, &sdnv_length);
if (sdnv_length == 0) {
expert_add_info(pinfo, sub_item, &ei_tcpclv3_segment_length);
return 1;
return 0;
}
offset += 1 + sdnv_length;
offset += sdnv_length;
const gint data_len_clamp = get_clamped_length(segment_length);
// implied transfer ID
xfer_id = wmem_map_lookup(ctx->tx_peer->frame_loc_to_transfer, ctx->cur_loc);
@ -1277,7 +1286,7 @@ dissect_v3_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
item_xfer_id = proto_tree_add_uint64(conv_tree, hf_tcpclv3_xfer_id, tvb, 0, 0, *xfer_id);
proto_item_set_generated(item_xfer_id);
proto_tree_add_item(conv_tree, hf_tcpclv3_data_segment_data, tvb, offset, segment_length, ENC_NA);
proto_tree_add_item(conv_tree, hf_tcpclv3_data_segment_data, tvb, offset, data_len_clamp, ENC_NA);
if (tcpcl_analyze_sequence) {
transfer_add_segment(ctx, *xfer_id, (conv_hdr & TCPCLV3_DATA_FLAGS), segment_length, pinfo, tvb, conv_tree, conv_item, item_flags);
@ -1290,7 +1299,7 @@ dissect_v3_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
&xfer_reassembly_table,
tvb, offset,
pinfo, 0, xfer_id,
segment_length,
data_len_clamp,
!(conv_hdr & TCPCLV3_DATA_END_FLAG)
);
ctx->xferload = process_reassembled_data(
@ -1310,9 +1319,8 @@ dissect_v3_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
/*No valid flags*/
offset += 1;
segment_length = evaluate_sdnv(tvb, offset, &sdnv_length);
sub_item = proto_tree_add_int(conv_tree, hf_tcpclv3_ack_length, tvb, offset, sdnv_length, segment_length);
if (segment_length < 0) {
sub_item = proto_tree_add_item_ret_varint(conv_tree, hf_tcpclv3_ack_length, tvb, offset, -1, ENC_VARINT_SDNV, &segment_length, &sdnv_length);
if (sdnv_length == 0) {
expert_add_info(pinfo, sub_item, &ei_tcpclv3_ack_length);
} else {
offset += sdnv_length;
@ -1889,10 +1897,10 @@ static guint get_message_len(packet_info *pinfo, tvbuff_t *tvb, int ext_offset,
guint8 version = tvb_get_guint8(tvb, offset);
offset += 1;
if (version == 3) {
offset += 3;
int bytecount;
int len = evaluate_sdnv(tvb, offset, &bytecount);
offset += len + 1;
offset += 3; // flags + keepalive
guint64 len;
guint bytecount = tvb_get_sdnv(tvb, offset, &len);
offset += bytecount+len;
}
else if (version == 4) {
offset += 1;
@ -1993,20 +2001,20 @@ static gint dissect_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
offset += 2;
/*
* New format Contact header has length field followed by Bundle Header.
* New format Contact header has length field followed by EID.
*/
guint64 eid_length;
int sdnv_length;
expert_field *ei_bundle_sdnv_length;
int eid_length = evaluate_sdnv_ei(tvb, offset, &sdnv_length, &ei_bundle_sdnv_length);
proto_item *item_len = proto_tree_add_int(tree_chdr, hf_tcpclv3_chdr_local_eid_length, tvb, offset, sdnv_length, eid_length);
offset += sdnv_length;
if (ei_bundle_sdnv_length) {
expert_add_info(pinfo, item_len, ei_bundle_sdnv_length);
return offset;
proto_item *sub_item = proto_tree_add_item_ret_varint(tree_chdr, hf_tcpclv3_chdr_local_eid_length, tvb, offset, -1, ENC_VARINT_SDNV, &eid_length, &sdnv_length);
if (sdnv_length == 0) {
expert_add_info(pinfo, sub_item, &ei_tcpclv3_eid_length);
return 0;
}
offset += sdnv_length;
const gint eid_len_clamp = get_clamped_length(eid_length);
proto_tree_add_item(tree_chdr, hf_tcpclv3_chdr_local_eid, tvb, offset, eid_length, ENC_NA|ENC_ASCII);
offset += eid_length;
proto_tree_add_item(tree_chdr, hf_tcpclv3_chdr_local_eid, tvb, offset, eid_len_clamp, ENC_NA|ENC_ASCII);
offset += eid_len_clamp;
// assumed parameters
ctx->tx_peer->segment_mru = G_MAXUINT64;

View File

@ -157,6 +157,7 @@ static ws_enum_t all_enums[] = {
ENUM(ENC_VARINT_PROTOBUF),
ENUM(ENC_VARINT_QUIC),
ENUM(ENC_VARINT_ZIGZAG),
ENUM(ENC_VARINT_SDNV),
ENUM(ENC_WINDOWS_1250),
ENUM(ENC_WINDOWS_1251),
ENUM(ENC_WINDOWS_1252),

View File

@ -3199,7 +3199,7 @@ proto_tree_add_item_ret_uint(proto_tree *tree, int hfindex, tvbuff_t *tvb,
proto_tree_set_uint(new_fi, value);
new_fi->flags |= (encoding & ENC_LITTLE_ENDIAN) ? FI_LITTLE_ENDIAN : FI_BIG_ENDIAN;
if (encoding & (ENC_VARINT_PROTOBUF|ENC_VARINT_ZIGZAG)) {
if (encoding & (ENC_VARINT_PROTOBUF|ENC_VARINT_ZIGZAG|ENC_VARINT_SDNV)) {
new_fi->flags |= FI_VARINT;
}
return proto_tree_add_node(tree, new_fi);
@ -3491,7 +3491,7 @@ proto_tree_add_item_ret_uint64(proto_tree *tree, int hfindex, tvbuff_t *tvb,
proto_tree_set_uint64(new_fi, value);
new_fi->flags |= (encoding & ENC_LITTLE_ENDIAN) ? FI_LITTLE_ENDIAN : FI_BIG_ENDIAN;
if (encoding & (ENC_VARINT_PROTOBUF|ENC_VARINT_ZIGZAG)) {
if (encoding & (ENC_VARINT_PROTOBUF|ENC_VARINT_ZIGZAG|ENC_VARINT_SDNV)) {
new_fi->flags |= FI_VARINT;
}
@ -3551,7 +3551,7 @@ proto_tree_add_item_ret_int64(proto_tree *tree, int hfindex, tvbuff_t *tvb,
proto_tree_set_int64(new_fi, value);
new_fi->flags |= (encoding & ENC_LITTLE_ENDIAN) ? FI_LITTLE_ENDIAN : FI_BIG_ENDIAN;
if (encoding & (ENC_VARINT_PROTOBUF | ENC_VARINT_ZIGZAG)) {
if (encoding & (ENC_VARINT_PROTOBUF|ENC_VARINT_ZIGZAG|ENC_VARINT_SDNV)) {
new_fi->flags |= FI_VARINT;
}
@ -3608,7 +3608,7 @@ proto_tree_add_item_ret_varint(proto_tree *tree, int hfindex, tvbuff_t *tvb,
proto_tree_set_uint64(new_fi, value);
new_fi->flags |= (encoding & ENC_LITTLE_ENDIAN) ? FI_LITTLE_ENDIAN : FI_BIG_ENDIAN;
if (encoding & (ENC_VARINT_PROTOBUF|ENC_VARINT_ZIGZAG)) {
if (encoding & (ENC_VARINT_PROTOBUF|ENC_VARINT_ZIGZAG|ENC_VARINT_SDNV)) {
new_fi->flags |= FI_VARINT;
}
@ -6062,7 +6062,7 @@ get_hfi_length(header_field_info *hfinfo, tvbuff_t *tvb, const gint start, gint
* of the string", and if the tvbuff if short, we just
* throw an exception.
*
* For ENC_VARINT_PROTOBUF|ENC_VARINT_QUIC|ENC_VARIANT_ZIGZAG, it means "find the end of the string",
* For ENC_VARINT_PROTOBUF|ENC_VARINT_QUIC|ENC_VARIANT_ZIGZAG|ENC_VARINT_SDNV, it means "find the end of the string",
* and if the tvbuff if short, we just throw an exception.
*
* It's not valid for any other type of field. For those
@ -6073,7 +6073,7 @@ get_hfi_length(header_field_info *hfinfo, tvbuff_t *tvb, const gint start, gint
* Length would run past the end of the packet.
*/
if ((IS_FT_INT(hfinfo->type)) || (IS_FT_UINT(hfinfo->type))) {
if (encoding & (ENC_VARINT_PROTOBUF|ENC_VARINT_ZIGZAG)) {
if (encoding & (ENC_VARINT_PROTOBUF|ENC_VARINT_ZIGZAG|ENC_VARINT_SDNV)) {
/*
* Leave the length as -1, so our caller knows
* it was -1.

View File

@ -639,8 +639,13 @@ void proto_report_dissector_bug(const char *format, ...)
* See https://developers.google.com/protocol-buffers/docs/encoding?csw=1#types
*/
#define ENC_VARINT_ZIGZAG 0x00000008
/*
* Decodes a variable-length integer used in DTN protocols
* See https://www.rfc-editor.org/rfc/rfc6256.html
*/
#define ENC_VARINT_SDNV 0x00000010
#define ENC_VARINT_MASK (ENC_VARINT_PROTOBUF|ENC_VARINT_QUIC|ENC_VARINT_ZIGZAG)
#define ENC_VARINT_MASK (ENC_VARINT_PROTOBUF|ENC_VARINT_QUIC|ENC_VARINT_ZIGZAG|ENC_VARINT_SDNV)
/* Values for header_field_info.display */

View File

@ -16,9 +16,12 @@
#include <string.h>
#include "tvbuff.h"
#include "proto.h"
#include "exceptions.h"
#include "wsutil/pint.h"
#include <ws_diag_control.h>
gboolean failed = FALSE;
typedef struct {
@ -605,6 +608,94 @@ run_tests(void)
tvb_free_chain(tvb_parent); /* should free all tvb's and associated data */
}
typedef struct
{
// Raw bytes
gint enc_len;
const guint8 *enc;
// Varint parameters
int encoding;
int maxlen;
// Results
unsigned long expect_except;
guint64 expect_val;
guint expect_len;
} varint_test_s;
DIAG_OFF_PEDANTIC
varint_test_s varint[] = {
{0, (const guint8 *)"", 0, FT_VARINT_MAX_LEN, DissectorError, 0, 0}, // no encoding specified
// ENC_VARINT_PROTOBUF
{0, (const guint8 *)"", ENC_VARINT_PROTOBUF, FT_VARINT_MAX_LEN, ReportedBoundsError, 0, 0},
{1, (const guint8 *)"\x00", ENC_VARINT_PROTOBUF, FT_VARINT_MAX_LEN, 0, 0, 1},
{1, (const guint8 *)"\x01", ENC_VARINT_PROTOBUF, FT_VARINT_MAX_LEN, 0, 1, 1},
{1, (const guint8 *)"\x7f", ENC_VARINT_PROTOBUF, FT_VARINT_MAX_LEN, 0, 0x7f, 1},
{2, (const guint8 *)"\x80\x01", ENC_VARINT_PROTOBUF, FT_VARINT_MAX_LEN, 0, 1ul<<7, 2},
{1, (const guint8 *)"\x80", ENC_VARINT_PROTOBUF, FT_VARINT_MAX_LEN, ReportedBoundsError, 0, 0}, // truncated data
{2, (const guint8 *)"\x80\x01", ENC_VARINT_PROTOBUF, 1, 0, 0, 0}, // truncated read
{5, (const guint8 *)"\x80\x80\x80\x80\x01", ENC_VARINT_PROTOBUF, FT_VARINT_MAX_LEN, 0, 1ul<<28, 5},
{10, (const guint8 *)"\x80\x80\x80\x80\x80\x80\x80\x80\x80\x01", ENC_VARINT_PROTOBUF, FT_VARINT_MAX_LEN, 0, 1ul<<63, 10},
{10, (const guint8 *)"\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01", ENC_VARINT_PROTOBUF, FT_VARINT_MAX_LEN, 0, 0xfffffffffffffffful, 10},
{10, (const guint8 *)"\x80\x80\x80\x80\x80\x80\x80\x80\x80\x02", ENC_VARINT_PROTOBUF, FT_VARINT_MAX_LEN, 0, 0, 10}, // overflow
// ENC_VARINT_SDNV
{0, (const guint8 *)"", ENC_VARINT_SDNV, FT_VARINT_MAX_LEN, ReportedBoundsError, 0, 0},
{1, (const guint8 *)"\x00", ENC_VARINT_SDNV, FT_VARINT_MAX_LEN, 0, 0, 1},
{1, (const guint8 *)"\x01", ENC_VARINT_SDNV, FT_VARINT_MAX_LEN, 0, 1, 1},
{1, (const guint8 *)"\x7f", ENC_VARINT_SDNV, FT_VARINT_MAX_LEN, 0, 0x7f, 1},
{2, (const guint8 *)"\x81\x00", ENC_VARINT_SDNV, FT_VARINT_MAX_LEN, 0, 1ul<<7, 2},
{1, (const guint8 *)"\x81", ENC_VARINT_SDNV, FT_VARINT_MAX_LEN, ReportedBoundsError, 1, 0}, // truncated data
{2, (const guint8 *)"\x81\x00", ENC_VARINT_SDNV, 1, 0, 1, 0}, // truncated read
{5, (const guint8 *)"\x81\x80\x80\x80\x00", ENC_VARINT_SDNV, FT_VARINT_MAX_LEN, 0, 1ul<<28, 5},
{10, (const guint8 *)"\x81\x80\x80\x80\x80\x80\x80\x80\x80\x00", ENC_VARINT_SDNV, FT_VARINT_MAX_LEN, 0, 1ul<<63, 10},
{10, (const guint8 *)"\x81\xff\xff\xff\xff\xff\xff\xff\xff\x7f", ENC_VARINT_SDNV, FT_VARINT_MAX_LEN, 0, 0xfffffffffffffffful, 10},
{10, (const guint8 *)"\x82\x80\x80\x80\x80\x80\x80\x80\x80\x00", ENC_VARINT_SDNV, FT_VARINT_MAX_LEN, 0, 1ul<<57, 0}, // overflow
};
DIAG_ON_PEDANTIC
static void
varint_tests(void)
{
tvbuff_t *tvb_parent, *tvb;
tvb_parent = tvb_new_real_data((const guint8*)"", 0, 0);
for (size_t ix = 0; ix < (sizeof(varint) / sizeof(varint_test_s)); ++ix) {
const varint_test_s *vit = &varint[ix];
tvb = tvb_new_child_real_data(tvb_parent, vit->enc, vit->enc_len, vit->enc_len);
unsigned long got_ex = 0;
guint64 got_val = 0;
guint got_len = 0;
TRY {
got_len = tvb_get_varint(tvb, 0, vit->maxlen, &got_val, vit->encoding);
}
CATCH_ALL {
got_ex = exc->except_id.except_code;
}
ENDTRY;
if (got_ex != vit->expect_except) {
printf("Failed varint #%zu with exception=%d while expected exception=%d\n",
ix, got_ex, vit->expect_except);
failed = TRUE;
continue;
}
if (got_val != vit->expect_val) {
printf("Failed varint #%zu value=%" PRIu64 " while expected value=%" PRIu64 "\n",
ix, got_val, vit->expect_val);
failed = TRUE;
continue;
}
if (got_len != vit->expect_len) {
printf("Failed varint #%zu length=%u while expected length=%u\n",
ix, got_len, vit->expect_len);
failed = TRUE;
continue;
}
printf("Passed varint #%zu\n", ix);
}
tvb_free_chain(tvb_parent); /* should free all tvb's and associated data */
}
/* Note: valgrind can be used to check for tvbuff memory leaks */
int
main(void)
@ -615,6 +706,7 @@ main(void)
except_init();
run_tests();
varint_tests();
except_deinit();
exit(failed?1:0);
}

View File

@ -4563,6 +4563,29 @@ tvb_get_varint(tvbuff_t *tvb, guint offset, guint maxlen, guint64 *value, const
break;
}
case ENC_VARINT_SDNV:
{
/* Decodes similar to protobuf but in MSByte order */
guint i;
guint64 b; /* current byte */
for (i = 0; ((i < FT_VARINT_MAX_LEN) && (i < maxlen)); ++i) {
b = tvb_get_guint8(tvb, offset++);
if ((i == 9) && (*value >= 1ul<<(64-7))) {
// guaranteed overflow, not valid SDNV
return 0;
}
*value <<= 7;
*value |= (b & 0x7F); /* add lower 7 bits to val */
if (b < 0x80) {
/* end successfully because of last byte's msb(most significant bit) is zero */
return i + 1;
}
}
break;
}
case ENC_VARINT_QUIC:
{
/* calculate variable length */

View File

@ -1145,7 +1145,7 @@ extern tvbuff_t* base64uri_tvb_to_new_tvb(tvbuff_t* parent, int offset, int leng
* @param offset The offset in tvb from which we begin trying to extract integer.
* @param maxlen The maximum distance from offset that we may try to extract integer
* @param value if parsing succeeds, parsed varint will store here.
* @param encoding The ENC_* that defines the format (e.g., ENC_VARINT_PROTOBUF, ENC_VARINT_QUIC, ENC_VARINT_ZIGZAG)
* @param encoding The ENC_* that defines the format (e.g., ENC_VARINT_PROTOBUF, ENC_VARINT_QUIC, ENC_VARINT_ZIGZAG, ENC_VARINT_SDNV)
* @return the length of this varint in tvb. 0 means parsing failed.
*/
WS_DLL_PUBLIC guint tvb_get_varint(tvbuff_t *tvb, guint offset, guint maxlen, guint64 *value, const guint encoding);