aboutsummaryrefslogtreecommitdiffstats
path: root/packet-vj.c
diff options
context:
space:
mode:
Diffstat (limited to 'packet-vj.c')
-rw-r--r--packet-vj.c762
1 files changed, 508 insertions, 254 deletions
diff --git a/packet-vj.c b/packet-vj.c
index fff8e31287..1c6cec5eae 100644
--- a/packet-vj.c
+++ b/packet-vj.c
@@ -1,7 +1,7 @@
/* packet-vj.c
* Routines for Van Jacobson header decompression.
*
- * $Id: packet-vj.c,v 1.8 2002/05/18 21:19:48 guy Exp $
+ * $Id: packet-vj.c,v 1.9 2002/05/20 00:56:30 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -10,7 +10,7 @@
* Copyright (c) 2001 by QUALCOMM, Incorporated.
* All Rights reserved.
*
- * Routines to compress and uncompress tcp packets (for transmission
+ * Routines to compress and uncompress TCP packets (for transmission
* over low speed serial lines).
*
* Copyright (c) 1989 Regents of the University of California.
@@ -72,34 +72,33 @@
#include <epan/packet.h>
#include "packet-ppp.h"
#include "ppptypes.h"
+#include "ipproto.h"
#include "in_cksum.h"
-#include "epan/tvbuff.h"
/* Define relevant IP/TCP parameters */
+#define IP_FIELD_TOT_LEN 2 /* Total length field in IP hdr */
+#define IP_FIELD_PROTOCOL 9 /* Protocol field byte in IP hdr */
+#define IP_ADDR_SIZE 4 /* Size in bytes of IPv4 address */
#define IP_FIELD_SRC 12 /* Byte 12 in IP hdr - src address */
#define IP_FIELD_DST 16 /* Byte 16 in IP hdr - dst address */
-#define IP_ADDR_SIZE 4 /* Size in bytes of IPv4 address */
-#define IP_FIELD_PROTOCOL 9 /* Protocol field byte in IP hdr */
-#define IP_PROTOCOL_TCP 0x06 /* Protocol field value for TCP */
#define IP_HDR_LEN 20 /* Minimum IP header length */
#define IP_HDR_LEN_MASK 0x0f /* Mask for header length field */
#define IP_MAX_OPT_LEN 44 /* Max length of IP options */
#define TCP_HDR_LEN 20 /* Minimum TCP header length */
#define TCP_MAX_OPT_LEN 44 /* Max length of TCP options */
-#define TCP_SIMUL_CONV 256 /* Number of simul. TCP conversations */
#define TCP_SIMUL_CONV_MAX 256 /* Max number of simul. TCP conversations */
-#define CHANGE_PUSH_BIT 0x10 /* TCP push bit changed */
#define TCP_PUSH_BIT 0x08 /* TCP push bit */
#define TCP_URG_BIT 0x20 /* TCP urgent bit */
/* Bits in first octet of compressed packet */
/* flag bits for what changed in a packet */
-#define NEW_C 0x40
-#define NEW_I 0x20
-#define NEW_S 0x08
-#define NEW_A 0x04
-#define NEW_W 0x02
-#define NEW_U 0x01
+#define NEW_C 0x40 /* Connection number changed */
+#define NEW_I 0x20 /* IP sequence number change by value != 1 */
+#define CHANGE_PUSH_BIT 0x10 /* TCP push bit set */
+#define NEW_S 0x08 /* Sequence number changed */
+#define NEW_A 0x04 /* Ack sequence number changed */
+#define NEW_W 0x02 /* Window changed */
+#define NEW_U 0x01 /* Urgent pointer present */
/* reserved, special-case values of above */
#define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */
@@ -113,9 +112,6 @@
/* Define for 0 */
#define ZERO 0
-/* Two byte CRC */
-#define CRC_LEN sizeof(guint16)
-
/* VJ Mem Chunk defines */
#define VJ_DATA_SIZE 128 /* Max IP hdr(64)+Max TCP hdr(64) */
#define VJ_ATOM_COUNT 250 /* Number of Atoms per block */
@@ -132,7 +128,7 @@ typedef struct {
guint16 cksum;
guint32 src;
guint32 dst;
-} iphdr_type;
+} iphdr_type;
typedef struct {
guint16 srcport;
@@ -169,6 +165,25 @@ typedef struct {
/* Initialize the protocol and registered fields */
static int proto_vj = -1;
+static int hf_vj_change_mask = -1;
+static int hf_vj_change_mask_c = -1;
+static int hf_vj_change_mask_i = -1;
+static int hf_vj_change_mask_p = -1;
+static int hf_vj_change_mask_s = -1;
+static int hf_vj_change_mask_a = -1;
+static int hf_vj_change_mask_w = -1;
+static int hf_vj_change_mask_u = -1;
+static int hf_vj_connection_number = -1;
+static int hf_vj_tcp_cksum = -1;
+static int hf_vj_urp = -1;
+static int hf_vj_win_delta = -1;
+static int hf_vj_ack_delta = -1;
+static int hf_vj_seq_delta = -1;
+static int hf_vj_ip_id_delta = -1;
+
+static gint ett_vj = -1;
+static gint ett_vj_changes = -1;
+
/* Protocol handles */
static dissector_handle_t ip_handle;
static dissector_handle_t data_handle;
@@ -180,113 +195,215 @@ static slcompress *rx_tx_state[RX_TX_STATE_COUNT] = {NULL, NULL};
/* Mem Chunks for storing decompressed headers */
static GMemChunk *vj_header_memchunk = NULL;
typedef struct {
- guint32 offset;
+ int offset; /* uppermost bit is "can't dissect" flag */
guint8 data[VJ_DATA_SIZE];
} vj_header_t;
/* Function prototypes */
-static void decodes(tvbuff_t *tvb, guint32 *offset, gint16 *val);
-static void decodel(tvbuff_t *tvb, guint32 *offset, gint32 *val);
+static int get_unsigned_delta(tvbuff_t *tvb, int *offsetp, int hf,
+ proto_tree *tree);
+static int get_signed_delta(tvbuff_t *tvb, int *offsetp, int hf,
+ proto_tree *tree);
static guint16 ip_csum(const guint8 *ptr, guint32 len);
-static slcompress *slhc_init(gint rslots);
+static slcompress *slhc_init(void);
static void vj_init(void);
-static gint vjuc_check(tvbuff_t *tvb, slcompress *comp);
+static gint vjuc_check(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ slcompress *comp);
static void vjuc_update_state(tvbuff_t *tvb, slcompress *comp, guint8 index);
static gint vjuc_tvb_setup(tvbuff_t *tvb, tvbuff_t **dst_tvb,
- slcompress *comp, frame_data *fd);
-static gint vjc_check(tvbuff_t *src_tvb, slcompress *comp);
-static gint vjc_update_state(tvbuff_t *src_tvb, slcompress *comp,
- frame_data *fd);
-static gint vjc_tvb_setup(tvbuff_t *src_tvb, tvbuff_t **dst_tvb,
- frame_data *fd);
+ packet_info *pinfo, slcompress *comp);
+static gint vjc_process(tvbuff_t *src_tvb, packet_info *pinfo, proto_tree *tree,
+ slcompress *comp);
+static gint vjc_tvb_setup(tvbuff_t *src_tvb, tvbuff_t **dst_tvb,
+ packet_info *pinfo);
/* Dissector for VJ Uncompressed packets */
static void
dissect_vjuc(tvbuff_t *tvb, packet_info *pinfo, proto_tree * tree)
{
+ proto_item *ti;
+ proto_tree *vj_tree = NULL;
+ slcompress *comp;
+ gint conn_index;
tvbuff_t *next_tvb = NULL;
- slcompress *comp = NULL;
- gint conn_index = ZERO;
- gint err = VJ_OK;
- /*
- * XXX - add error information to the Info column?
- */
- if(check_col(pinfo->cinfo, COL_INFO))
- col_set_str(pinfo->cinfo, COL_INFO, "VJ uncompressed TCP");
+ if(check_col(pinfo->cinfo, COL_PROTOCOL))
+ col_set_str(pinfo->cinfo, COL_INFO, "PPP VJ");
+
+ if(tree != NULL) {
+ ti = proto_tree_add_protocol_format(tree, proto_vj, tvb, 0, -1,
+ "PPP VJ Compression: Uncompressed data");
+ vj_tree = proto_item_add_subtree(ti, ett_vj);
+ }
+
+ if(!ppp_vj_decomp) {
+ /* VJ decompression turned off */
+ if(check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "VJ uncompressed TCP (decompression disabled)");
+ if(tree != NULL)
+ call_dissector(data_handle, tvb, pinfo, vj_tree);
+ return;
+ }
- /* Return if VJ is off or direction is not known */
- if(ppp_vj_decomp == FALSE || pinfo->p2p_dir == P2P_DIR_UNKNOWN)
- err = VJ_ERROR;
+ if(pinfo->p2p_dir == P2P_DIR_UNKNOWN) {
+ /* Direction of the traffic unknown - can't decompress */
+ if(check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "VJ uncompressed TCP (direction unknown)");
+ if(tree != NULL)
+ call_dissector(data_handle, tvb, pinfo, vj_tree);
+ return;
+ }
- if((comp = rx_tx_state[pinfo->p2p_dir]) == NULL)
- err = VJ_ERROR;
+ if((comp = rx_tx_state[pinfo->p2p_dir]) == NULL) {
+ /* No state information found - can't decompress */
+ if(check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "VJ uncompressed TCP (no state information)");
+ if(tree != NULL)
+ call_dissector(data_handle, tvb, pinfo, vj_tree);
+ return;
+ }
/* Check if packet malformed. */
- if(err == VJ_OK)
- err = conn_index = vjuc_check(tvb, comp);
+ conn_index = vjuc_check(tvb, pinfo, vj_tree, comp);
+ if(conn_index == VJ_ERROR)
+ return;
/* Set up tvb containing decompressed packet */
- if(err != VJ_ERROR)
- err = vjuc_tvb_setup(tvb, &next_tvb, comp, pinfo->fd);
+ if(vjuc_tvb_setup(tvb, &next_tvb, pinfo, comp) == VJ_ERROR)
+ return;
- /* If packet seen for first time update state */
- if(pinfo->fd->flags.visited != 1 && err == VJ_OK)
+ /*
+ * No errors, so:
+ *
+ * if packet seen for first time update state;
+ * call IP dissector.
+ */
+ if(!pinfo->fd->flags.visited)
vjuc_update_state(next_tvb, comp, conn_index);
-
- /* If no errors call IP dissector else dissect as data. */
- if(err == VJ_OK)
- call_dissector(ip_handle, next_tvb, pinfo, tree);
- else
- call_dissector(data_handle, tvb, pinfo, tree);
+ call_dissector(ip_handle, next_tvb, pinfo, tree);
}
/* Dissector for VJ Compressed packets */
static void
dissect_vjc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
+ proto_item *ti;
+ proto_tree *vj_tree = NULL;
tvbuff_t *next_tvb = NULL;
slcompress *comp = NULL;
- gint err = VJ_OK;
+ gint err = VJ_ERROR;
- /*
- * XXX - add error information to the Info column?
- */
- if(check_col(pinfo->cinfo, COL_INFO))
- col_set_str(pinfo->cinfo, COL_INFO, "VJ compressed TCP");
+ if(check_col(pinfo->cinfo, COL_PROTOCOL))
+ col_set_str(pinfo->cinfo, COL_INFO, "PPP VJ");
- /* Return if VJ is off or direction is not known */
- if(ppp_vj_decomp == FALSE || pinfo->p2p_dir == P2P_DIR_UNKNOWN)
- err = VJ_ERROR;
-
- if((comp = rx_tx_state[pinfo->p2p_dir]) == NULL)
- err = VJ_ERROR;
+ if(tree != NULL) {
+ ti = proto_tree_add_protocol_format(tree, proto_vj, tvb, 0, -1,
+ "PPP VJ Compression: Compressed data");
+ vj_tree = proto_item_add_subtree(ti, ett_vj);
+ }
- /* Check if packet malformed. */
- if(err != VJ_ERROR)
- err = vjc_check(tvb, comp);
+ if(!ppp_vj_decomp) {
+ /* VJ decompression turned off */
+ if(check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "VJ compressed TCP (decompression disabled)");
+ if(tree != NULL)
+ call_dissector(data_handle, tvb, pinfo, vj_tree);
+ return;
+ }
- /* If packet seen for first time update state */
- if(pinfo->fd->flags.visited != 1 && err == VJ_OK) {
- err = vjc_update_state(tvb, comp, pinfo->fd);
+ if(pinfo->p2p_dir == P2P_DIR_UNKNOWN) {
+ /* Direction of the traffic unknown - can't decompress */
+ if(check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "VJ compressed TCP (direction unknown)");
+ if(tree != NULL)
+ call_dissector(data_handle, tvb, pinfo, vj_tree);
+ return;
}
- /* Set up tvb containing decompressed packet */
- if(err == VJ_OK)
- err = vjc_tvb_setup(tvb, &next_tvb, pinfo->fd);
+ if((comp = rx_tx_state[pinfo->p2p_dir]) == NULL) {
+ /* No state information found - can't decompress */
+ if(check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "VJ compressed TCP (no state information)");
+ if(tree != NULL)
+ call_dissector(data_handle, tvb, pinfo, vj_tree);
+ return;
+ }
- /* If no errors call IP dissector else dissect as data */
- if(err == VJ_OK)
- call_dissector(ip_handle, next_tvb, pinfo, tree);
- else
- call_dissector(data_handle, tvb, pinfo, tree);
+ /* Process the compressed data header */
+ if(vjc_process(tvb, pinfo, vj_tree, comp) == VJ_ERROR)
+ return;
+
+ /* Not malformed - set up tvb containing decompressed packet */
+ err = vjc_tvb_setup(tvb, &next_tvb, pinfo);
+ if(err == VJ_ERROR) {
+ if(tree != NULL)
+ call_dissector(data_handle, tvb, pinfo, vj_tree);
+ return;
+ }
+
+ /* No errors, so call IP dissector */
+ call_dissector(ip_handle, next_tvb, pinfo, tree);
}
-/* Registeration functions for dissectors */
+/* Registration functions for dissectors */
void
proto_register_vj(void)
{
+ static hf_register_info hf[] = {
+ { &hf_vj_change_mask,
+ { "Change mask", "vj.change_mask", FT_UINT8, BASE_HEX,
+ NULL, 0x0, "", HFILL }},
+ { &hf_vj_change_mask_c,
+ { "Connection changed", "vj.change_mask_c", FT_BOOLEAN, 8,
+ NULL, NEW_C, "Connection number changed", HFILL }},
+ { &hf_vj_change_mask_i,
+ { "IP ID change != 1", "vj.change_mask_i", FT_BOOLEAN, 8,
+ NULL, NEW_I, "IP ID changed by a value other than 1", HFILL }},
+ { &hf_vj_change_mask_p,
+ { "Push bit set", "vj.change_mask_p", FT_BOOLEAN, 8,
+ NULL, CHANGE_PUSH_BIT, "TCP PSH flag set", HFILL }},
+ { &hf_vj_change_mask_s,
+ { "Sequence number changed", "vj.change_mask_s", FT_BOOLEAN, 8,
+ NULL, NEW_S, "Sequence number changed", HFILL }},
+ { &hf_vj_change_mask_a,
+ { "Ack number changed", "vj.change_mask_a", FT_BOOLEAN, 8,
+ NULL, NEW_A, "Acknowledgement sequence number changed", HFILL }},
+ { &hf_vj_change_mask_w,
+ { "Window changed", "vj.change_mask_w", FT_BOOLEAN, 8,
+ NULL, NEW_W, "TCP window changed", HFILL }},
+ { &hf_vj_change_mask_u,
+ { "Urgent pointer set", "vj.change_mask_u", FT_BOOLEAN, 8,
+ NULL, NEW_U, "Urgent pointer set", HFILL }},
+ { &hf_vj_connection_number,
+ { "Connection number", "vj.connection_number", FT_UINT8, BASE_DEC,
+ NULL, 0x0, "Connection number", HFILL }},
+ { &hf_vj_tcp_cksum,
+ { "TCP checksum", "vj.tcp_cksum", FT_UINT16, BASE_HEX,
+ NULL, 0x0, "TCP checksum", HFILL }},
+ { &hf_vj_urp,
+ { "Urgent pointer", "vj.urp", FT_UINT16, BASE_DEC,
+ NULL, 0x0, "Urgent pointer", HFILL }},
+ { &hf_vj_win_delta,
+ { "Window delta", "vj.win_delta", FT_INT16, BASE_DEC,
+ NULL, 0x0, "Delta for window", HFILL }},
+ { &hf_vj_ack_delta,
+ { "Ack delta", "vj.ack_delta", FT_UINT16, BASE_DEC,
+ NULL, 0x0, "Delta for acknowledgment sequence number", HFILL }},
+ { &hf_vj_seq_delta,
+ { "Sequence delta", "vj.seq_delta", FT_UINT16, BASE_DEC,
+ NULL, 0x0, "Delta for sequence number", HFILL }},
+ { &hf_vj_ip_id_delta,
+ { "IP ID delta", "vj.ip_id_delta", FT_UINT16, BASE_DEC,
+ NULL, 0x0, "Delta for IP ID", HFILL }},
+ };
+ static gint *ett[] = {
+ &ett_vj,
+ &ett_vj_changes,
+ };
+
proto_vj = proto_register_protocol("PPP VJ Compression", "PPP VJ", "vj");
+ proto_register_field_array(proto_vj, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
register_init_routine(&vj_init);
}
@@ -325,30 +442,27 @@ vj_init(void)
g_free(pstate);
g_free(pslc);
}
- rx_tx_state[i] = slhc_init(TCP_SIMUL_CONV);
+ rx_tx_state[i] = slhc_init();
}
return;
}
/* Initialization routine for VJ decompression */
static slcompress *
-slhc_init(gint rslots)
+slhc_init(void)
{
- size_t rsize = rslots * sizeof(cstate);
+ size_t rsize = TCP_SIMUL_CONV_MAX * sizeof(cstate);
slcompress *comp = g_malloc(sizeof(slcompress));
- if(rslots < ZERO || rslots > TCP_SIMUL_CONV_MAX)
- return NULL;
-
- if (comp != NULL) {
+ if(comp != NULL) {
memset(comp, ZERO, sizeof(slcompress));
- if ((comp->rstate = g_malloc(rsize)) == NULL) {
+ if((comp->rstate = g_malloc(rsize)) == NULL) {
g_free(comp);
comp = NULL;
}
else {
memset(comp->rstate, ZERO, rsize);
- comp->rslot_limit = rslots - 1;
+ comp->rslot_limit = TCP_SIMUL_CONV_MAX - 1;
comp->recv_current = TCP_SIMUL_CONV_MAX - 1;
comp->flags |= SLF_TOSS;
}
@@ -360,222 +474,359 @@ slhc_init(gint rslots)
static gint
vjc_tvb_setup(tvbuff_t *src_tvb,
tvbuff_t **dst_tvb,
- frame_data * fd)
+ packet_info *pinfo)
{
vj_header_t *hdr_buf;
+ guint8 offset;
guint8 *data_ptr;
- guint8 *pbuf = NULL;
- gint hdr_len = ZERO;
- gint buf_len = ZERO;
- guint8 offset = ZERO;
+ iphdr_type *ip;
+ tcphdr_type *thp;
+ gint hdr_len;
+ gint buf_len;
+ guint8 *pbuf;
g_assert(src_tvb);
/* Get decompressed header stored in fd protocol area */
- hdr_buf = p_get_proto_data(fd, proto_vj);
- if(hdr_buf == NULL)
+ hdr_buf = p_get_proto_data(pinfo->fd, proto_vj);
+ if(hdr_buf == NULL) {
+ if(check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "VJ compressed TCP (decompressed data not available)");
return VJ_ERROR;
+ }
+
+ if(check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "VJ compressed TCP");
/* Get the data offset in the tvbuff */
offset = hdr_buf->offset;
/* Copy header and form tvb */
data_ptr = hdr_buf->data;
- hdr_len = lo_nibble(((iphdr_type *)data_ptr)->ihl_version) * 4;
- hdr_len += TCP_OFFSET(((tcphdr_type *)(data_ptr + hdr_len))) * 4;
+ ip = (iphdr_type *)data_ptr;
+ hdr_len = lo_nibble(ip->ihl_version) * 4;
+ thp = (tcphdr_type *)(data_ptr + hdr_len);
+ hdr_len += TCP_OFFSET(thp) * 4;
buf_len = tvb_length(src_tvb) + hdr_len - offset;
- pbuf = g_malloc(buf_len);
+ pbuf = g_malloc(buf_len);
memcpy(pbuf, data_ptr, hdr_len);
tvb_memcpy(src_tvb, pbuf + hdr_len, offset, buf_len - hdr_len);
- *dst_tvb = tvb_new_real_data(pbuf, buf_len, buf_len);
+ *dst_tvb = tvb_new_real_data(pbuf, buf_len, ntohs(ip->tot_len));
tvb_set_child_real_data_tvbuff(src_tvb, *dst_tvb);
- add_new_data_source(fd, *dst_tvb, "VJ Decompressed");
+ add_new_data_source(pinfo->fd, *dst_tvb, "VJ Decompressed");
return VJ_OK;
}
-/* For VJ compressed packets update the decompressor state */
+/*
+ * For VJ compressed packet:
+ *
+ * check if it is malformed;
+ * dissect the relevant fields;
+ * update the decompressor state on the first pass.
+ */
static gint
-vjc_update_state(tvbuff_t *src_tvb, slcompress *comp, frame_data *fd)
+vjc_process(tvbuff_t *src_tvb, packet_info *pinfo, proto_tree *tree,
+ slcompress *comp)
{
+ int offset = ZERO;
+ gint changes;
+ proto_item *ti;
+ proto_tree *changes_tree;
+ guint8 conn_index;
+ cstate *cs;
+ iphdr_type *ip;
+ tcphdr_type *thp;
+ guint16 tcp_cksum;
+ gint hdrlen = ZERO;
+ guint16 word;
+ int delta;
+ gint len;
vj_header_t *buf_hdr;
guint8 *data_ptr;
- cstate *cs = &comp->rstate[comp->recv_current];
- tcphdr_type *thp = &cs->cs_tcp;
- iphdr_type *ip = &cs->cs_ip;
- gint changes = ZERO;
- gint len = ZERO;
- gint hdrlen = ZERO;
- guint32 offset = ZERO;
- guint16 word = ZERO;
- g_assert(src_tvb);
- g_assert(comp);
- g_assert(fd);
+ if(tvb_length(src_tvb) < 3){
+ if(check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "VJ compressed TCP (not enough data available)");
+ if(tree != NULL)
+ call_dissector(data_handle, src_tvb, pinfo, tree);
+ comp->flags |= SLF_TOSS;
+ return VJ_ERROR;
+ }
/* Read the change byte */
- changes = tvb_get_guint8(src_tvb, offset++);
- if(changes & NEW_C)
- offset++;
+ changes = tvb_get_guint8(src_tvb, offset);
+ if(tree != NULL) {
+ switch (changes & SPECIALS_MASK) {
+
+ case SPECIAL_I:
+ ti = proto_tree_add_uint_format(tree, hf_vj_change_mask, src_tvb,
+ offset, 1, changes,
+ "Change mask: 0x%02x (echoed interactive traffic)",
+ changes);
+ break;
+
+ case SPECIAL_D:
+ ti = proto_tree_add_uint_format(tree, hf_vj_change_mask, src_tvb,
+ offset, 1, changes,
+ "Change mask: 0x%02x (unidirectional data)",
+ changes);
+ break;
+
+ default:
+ /*
+ * XXX - summarize bits?
+ */
+ ti = proto_tree_add_uint_format(tree, hf_vj_change_mask, src_tvb,
+ offset, 1, changes,
+ "Change mask: 0x%02x", changes);
+ break;
+ }
+ changes_tree = proto_item_add_subtree(ti, ett_vj_changes);
+ proto_tree_add_boolean(changes_tree, hf_vj_change_mask_c, src_tvb,
+ offset, 1, changes);
+ proto_tree_add_boolean(changes_tree, hf_vj_change_mask_i, src_tvb,
+ offset, 1, changes);
+ proto_tree_add_boolean(changes_tree, hf_vj_change_mask_p, src_tvb,
+ offset, 1, changes);
+ proto_tree_add_boolean(changes_tree, hf_vj_change_mask_s, src_tvb,
+ offset, 1, changes);
+ proto_tree_add_boolean(changes_tree, hf_vj_change_mask_a, src_tvb,
+ offset, 1, changes);
+ proto_tree_add_boolean(changes_tree, hf_vj_change_mask_w, src_tvb,
+ offset, 1, changes);
+ proto_tree_add_boolean(changes_tree, hf_vj_change_mask_u, src_tvb,
+ offset, 1, changes);
+ }
+ offset++;
+
+ if(changes & NEW_C){ /* Read conn index */
+ conn_index = tvb_get_guint8(src_tvb, offset);
+ if(tree != NULL)
+ proto_tree_add_uint(tree, hf_vj_connection_number, src_tvb, offset, 1,
+ conn_index);
+ offset++;
+ if(conn_index > comp->rslot_limit) {
+ if(check_col(pinfo->cinfo, COL_INFO)) {
+ col_add_fstr(pinfo->cinfo, COL_INFO, "VJ compressed TCP (index (%u) < highest receive slot ID (%u))",
+ conn_index, comp->rslot_limit);
+ }
+ comp->flags |= SLF_TOSS;
+ return VJ_ERROR;
+ }
+ comp->flags &= ~SLF_TOSS;
+ comp->recv_current = conn_index;
+ }
+ else {
+ if(comp->flags & SLF_TOSS) {
+ if(check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "VJ compressed TCP (previous data bad)");
+ return VJ_ERROR;
+ }
+ }
+
+ cs = &comp->rstate[comp->recv_current];
+ thp = &cs->cs_tcp;
+ ip = &cs->cs_ip;
/* Build TCP and IP headers */
- hdrlen = lo_nibble(ip->ihl_version) * 4 + TCP_OFFSET(thp) * 4;
- thp->cksum = htons(tvb_get_ntohs(src_tvb, offset));
+ tcp_cksum = tvb_get_ntohs(src_tvb, offset);
+ if(tree != NULL)
+ proto_tree_add_uint(tree, hf_vj_tcp_cksum, src_tvb, offset, 2, tcp_cksum);
+ if(!pinfo->fd->flags.visited) {
+ hdrlen = lo_nibble(ip->ihl_version) * 4 + TCP_OFFSET(thp) * 4;
+ thp->cksum = htons(tcp_cksum);
+ }
offset += 2;
- if (changes & CHANGE_PUSH_BIT)
- thp->flags |= TCP_PUSH_BIT;
- else
- thp->flags &= ~TCP_PUSH_BIT;
+ if(!pinfo->fd->flags.visited) {
+ if(changes & CHANGE_PUSH_BIT)
+ thp->flags |= TCP_PUSH_BIT;
+ else
+ thp->flags &= ~TCP_PUSH_BIT;
+ }
/* Deal with special cases and normal deltas */
switch(changes & SPECIALS_MASK){
case SPECIAL_I: /* Echoed terminal traffic */
- word = ntohs(ip->tot_len) - hdrlen;
- thp->ack_seq = htonl( ntohl(thp->ack_seq) + word);
- thp->seq = htonl( ntohl(thp->seq) + word);
- break;
+ if(!pinfo->fd->flags.visited) {
+ word = ntohs(ip->tot_len) - hdrlen;
+ thp->ack_seq = htonl(ntohl(thp->ack_seq) + word);
+ thp->seq = htonl(ntohl(thp->seq) + word);
+ }
+ break;
case SPECIAL_D: /* Unidirectional data */
- thp->seq = htonl( ntohl(thp->seq) + ntohs(ip->tot_len) - hdrlen);
- break;
+ if(!pinfo->fd->flags.visited)
+ thp->seq = htonl(ntohl(thp->seq) + ntohs(ip->tot_len) - hdrlen);
+ break;
default:
if(changes & NEW_U){
- thp->urg_ptr = ZERO;
- decodes(src_tvb, &offset, &thp->urg_ptr);
- thp->flags |= TCP_URG_BIT;
- }
- else
- thp->flags &= ~TCP_URG_BIT;
- if(changes & NEW_W)
- decodes(src_tvb, &offset, &thp->window);
- if(changes & NEW_A)
- decodel(src_tvb, &offset, &thp->ack_seq);
- if(changes & NEW_S)
- decodel(src_tvb, &offset, &thp->seq);
- break;
+ delta = get_unsigned_delta(src_tvb, &offset, hf_vj_urp, tree);
+ if(!pinfo->fd->flags.visited) {
+ thp->urg_ptr = delta;
+ thp->flags |= TCP_URG_BIT;
+ }
+ } else {
+ if(!pinfo->fd->flags.visited)
+ thp->flags &= ~TCP_URG_BIT;
+ }
+ if(changes & NEW_W) {
+ delta = get_signed_delta(src_tvb, &offset, hf_vj_win_delta, tree);
+ if(!pinfo->fd->flags.visited)
+ thp->window = htons(ntohs(thp->window) + delta);
+ }
+ if(changes & NEW_A) {
+ delta = get_unsigned_delta(src_tvb, &offset, hf_vj_ack_delta, tree);
+ if(!pinfo->fd->flags.visited)
+ thp->ack_seq = htonl(ntohl(thp->ack_seq) + delta);
+ }
+ if(changes & NEW_S) {
+ delta = get_unsigned_delta(src_tvb, &offset, hf_vj_seq_delta, tree);
+ if(!pinfo->fd->flags.visited)
+ thp->seq = htonl(ntohl(thp->seq) + delta);
+ }
+ break;
}
if(changes & NEW_I)
- decodes(src_tvb, &offset, &ip->id);
+ delta = get_unsigned_delta(src_tvb, &offset, hf_vj_ip_id_delta, tree);
else
- ip->id = htons (ntohs (ip->id) + 1);
-
- /* Compute ip packet length and the buffer length needed */
- if((len = tvb_length(src_tvb) - offset - CRC_LEN) < ZERO) {
+ delta = 1;
+ if(!pinfo->fd->flags.visited)
+ ip->id = htons(ntohs(ip->id) + delta);
+
+ /* Compute IP packet length and the buffer length needed */
+ len = tvb_reported_length_remaining(src_tvb, offset);
+ if(len < ZERO) {
+ /*
+ * This shouldn't happen, as we *were* able to fetch stuff right before
+ * offset.
+ */
+ if(check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "VJ compressed TCP (not enough data available)");
comp->flags |= SLF_TOSS;
return VJ_ERROR;
}
- len += hdrlen;
- ip->tot_len = htons(len);
- /* Compute IP check sum */
- ip->cksum = ZERO;
- ip->cksum = ip_csum((guint8 *)ip, lo_nibble(ip->ihl_version) * 4);
-
- /* Store the reconstructed header in frame data area */
- buf_hdr = g_mem_chunk_alloc(vj_header_memchunk);
- buf_hdr->offset = offset; /* Offset in tvbuff is also stored */
- data_ptr = buf_hdr->data;
- memcpy(data_ptr, ip, IP_HDR_LEN);
- data_ptr += IP_HDR_LEN;
- if(lo_nibble(ip->ihl_version) > 5) {
- memcpy(data_ptr, cs->cs_ipopt, (lo_nibble(ip->ihl_version) - 5) * 4);
- data_ptr += (lo_nibble(ip->ihl_version) - 5) * 4;
- }
- memcpy(data_ptr, thp, TCP_HDR_LEN);
- data_ptr += TCP_HDR_LEN;
- if(TCP_OFFSET(thp) > 5)
- memcpy(data_ptr, cs->cs_tcpopt, (TCP_OFFSET(thp) - 5) * 4);
- p_add_proto_data(fd, proto_vj, buf_hdr);
-
- return VJ_OK;
-}
-
-/* For VJ compressed packet check if it is malformed */
-static gint
-vjc_check(tvbuff_t *src_tvb, slcompress *comp)
-{
- guint8 conn_index = ZERO;
- guint8 offset = ZERO;
- gint changes = ZERO;
-
- g_assert(src_tvb);
- g_assert(comp);
- if(tvb_length(src_tvb) < 3){
- comp->flags |= SLF_TOSS;
- return VJ_ERROR;
+ if(!pinfo->fd->flags.visited) {
+ len += hdrlen;
+ ip->tot_len = htons(len);
+ /* Compute IP check sum */
+ ip->cksum = ZERO;
+ ip->cksum = ip_csum((guint8 *)ip, lo_nibble(ip->ihl_version) * 4);
+
+ /* Store the reconstructed header in frame data area */
+ buf_hdr = g_mem_chunk_alloc(vj_header_memchunk);
+ buf_hdr->offset = offset; /* Offset in tvbuff is also stored */
+ data_ptr = buf_hdr->data;
+ memcpy(data_ptr, ip, IP_HDR_LEN);
+ data_ptr += IP_HDR_LEN;
+ if(lo_nibble(ip->ihl_version) > 5) {
+ memcpy(data_ptr, cs->cs_ipopt, (lo_nibble(ip->ihl_version) - 5) * 4);
+ data_ptr += (lo_nibble(ip->ihl_version) - 5) * 4;
+ }
+ memcpy(data_ptr, thp, TCP_HDR_LEN);
+ data_ptr += TCP_HDR_LEN;
+ if(TCP_OFFSET(thp) > 5)
+ memcpy(data_ptr, cs->cs_tcpopt, (TCP_OFFSET(thp) - 5) * 4);
+ p_add_proto_data(pinfo->fd, proto_vj, buf_hdr);
}
- /* Read the change byte */
- changes = tvb_get_guint8(src_tvb, offset++);
+ if(tree != NULL && tvb_offset_exists(src_tvb, offset))
+ proto_tree_add_text(tree, src_tvb, offset, -1, "TCP payload");
- if(changes & NEW_C){ /* Read conn index */
- conn_index = tvb_get_guint8(src_tvb, offset++);
- if(conn_index > comp->rslot_limit) {
- comp->flags |= SLF_TOSS;
- return VJ_ERROR;
- }
- comp->flags &= ~SLF_TOSS;
- comp->recv_current = conn_index;
- }
- else {
- if(comp->flags & SLF_TOSS)
- return VJ_ERROR;
- }
-
return VJ_OK;
}
-/* Decode the delta of a 32 bit header field */
-static void
-decodel(tvbuff_t *tvb, guint32* offset, gint32 *val)
+/*
+ * Get an unsigned delta for a field, and put it into the protocol tree if
+ * we're building a protocol tree.
+ */
+static int
+get_unsigned_delta(tvbuff_t *tvb, int *offsetp, int hf, proto_tree *tree)
{
- gint del = tvb_get_guint8(tvb, (*offset)++);
+ int offset = *offsetp;
+ int len;
+ guint16 del;
+
+ len = 1;
+ del = tvb_get_guint8(tvb, offset++);
if(del == ZERO){
- del = tvb_get_ntohs(tvb, *offset);
- *offset= *offset + 2;
+ del = tvb_get_ntohs(tvb, offset);
+ offset += 2;
+ len += 2;
}
- *val = htonl(ntohl(*val) + del);
- return;
+ if(tree != NULL)
+ proto_tree_add_uint(tree, hf, tvb, *offsetp, len, del);
+ *offsetp = offset;
+ return del;
}
-/* Decode the delta of a 16 bit header field */
-static void
-decodes(tvbuff_t *tvb, guint32* offset, gint16 *val)
+/*
+ * Get a signed delta for a field, and put it into the protocol tree if
+ * we're building a protocol tree.
+ */
+static int
+get_signed_delta(tvbuff_t *tvb, int *offsetp, int hf, proto_tree *tree)
{
- gint del = tvb_get_guint8(tvb, (*offset)++);
+ int offset = *offsetp;
+ int len;
+ gint16 del;
+
+ len = 1;
+ del = tvb_get_guint8(tvb, offset++);
if(del == ZERO){
- del = tvb_get_ntohs(tvb, *offset);
- *offset= *offset + 2;
+ del = tvb_get_ntohs(tvb, offset);
+ offset += 2;
+ len += 2;
}
- *val = htons(ntohs(*val) + del);
- return;
+ if(tree != NULL)
+ proto_tree_add_int(tree, hf, tvb, *offsetp, len, del);
+ *offsetp = offset;
+ return del;
}
/* For VJ uncompressed packet check if it is malformed */
static gint
-vjuc_check(tvbuff_t *tvb, slcompress *comp)
+vjuc_check(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ slcompress *comp)
{
- guint8 ihl = ZERO;
- gint index = ZERO;
-
- g_assert(comp);
- g_assert(tvb);
+ guint8 ihl;
+ gint index;
if(tvb_length(tvb) < IP_HDR_LEN) {
+ if(check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "VJ uncompressed TCP (not enough data available)");
+ if(tree != NULL)
+ call_dissector(data_handle, tvb, pinfo, tree);
comp->flags |= SLF_TOSS;
- index = VJ_ERROR;
+ return VJ_ERROR;
}
- else {
- /* Get the IP header length */
- ihl = tvb_get_guint8(tvb, 0) & IP_HDR_LEN_MASK;
- ihl <<= 2;
- /* Get connection index */
- index = tvb_get_guint8(tvb, IP_FIELD_PROTOCOL);
+ /* Get the IP header length */
+ ihl = tvb_get_guint8(tvb, 0) & IP_HDR_LEN_MASK;
+ ihl <<= 2;
+
+ /* Get connection index */
+ index = tvb_get_guint8(tvb, IP_FIELD_PROTOCOL);
+ if(tree != NULL)
+ proto_tree_add_uint(tree, hf_vj_connection_number, tvb,
+ IP_FIELD_PROTOCOL, 1, index);
+
+ /* Check connection number and IP header length field */
+ if(ihl < IP_HDR_LEN) {
+ if(check_col(pinfo->cinfo, COL_INFO)) {
+ col_add_fstr(pinfo->cinfo, COL_INFO, "VJ uncompressed TCP (header length (%u) < %u)",
+ ihl, IP_HDR_LEN);
+ }
+ comp->flags |= SLF_TOSS;
+ return VJ_ERROR;
+ }
- /* Check connection number and IP header length field */
- if(ihl < IP_HDR_LEN || index > comp->rslot_limit) {
- comp->flags |= SLF_TOSS;
- index = VJ_ERROR;
+ if(index > comp->rslot_limit) {
+ if(check_col(pinfo->cinfo, COL_INFO)) {
+ col_add_fstr(pinfo->cinfo, COL_INFO, "VJ uncompressed TCP (index (%u) < highest receive slot ID (%u))",
+ index, comp->rslot_limit);
}
+ comp->flags |= SLF_TOSS;
+ return VJ_ERROR;
}
return index;
@@ -584,16 +835,14 @@ vjuc_check(tvbuff_t *tvb, slcompress *comp)
/* Setup the decompressed packet tvb for VJ uncompressed packets */
static gint
vjuc_tvb_setup(tvbuff_t *tvb,
- tvbuff_t **dst_tvb,
- slcompress *comp,
- frame_data *fd)
+ tvbuff_t **dst_tvb,
+ packet_info *pinfo,
+ slcompress *comp)
{
- guint8 ihl = ZERO;
- gint isize = tvb_length(tvb);
- guint8 *buffer = NULL;
-
- g_assert(comp);
- g_assert(tvb);
+ frame_data *fd = pinfo->fd;
+ guint8 ihl = ZERO;
+ gint isize = tvb_length(tvb);
+ guint8 *buffer = NULL;
/* Get the IP header length */
ihl = tvb_get_guint8(tvb, 0) & IP_HDR_LEN_MASK;
@@ -602,20 +851,25 @@ vjuc_tvb_setup(tvbuff_t *tvb,
/* Copy packet data to a buffer */
buffer = g_malloc(isize);
tvb_memcpy(tvb, buffer, 0, isize);
- buffer[IP_FIELD_PROTOCOL] = IP_PROTOCOL_TCP;
+ buffer[IP_FIELD_PROTOCOL] = IP_PROTO_TCP;
/* Compute checksum */
- if (ip_csum(buffer, ihl) != ZERO) {
+ if(ip_csum(buffer, ihl) != ZERO) {
g_free(buffer);
+ if(check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "VJ uncompressed TCP (bad IP checksum)");
comp->flags |= SLF_TOSS;
return VJ_ERROR;
}
+ if(check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "VJ uncompressed TCP");
+
/*
* Form the new tvbuff.
* Neither header checksum is recalculated
*/
- *dst_tvb = tvb_new_real_data(buffer, isize, isize);
+ *dst_tvb = tvb_new_real_data(buffer, isize, pntohs(&buffer[IP_FIELD_TOT_LEN]));
tvb_set_child_real_data_tvbuff(tvb, *dst_tvb);
add_new_data_source(fd, *dst_tvb, "VJ Uncompressed");
return VJ_OK;
@@ -640,21 +894,21 @@ vjuc_update_state(tvbuff_t *tvb, slcompress *comp, guint8 index)
comp->flags &= ~SLF_TOSS;
tvb_memcpy(tvb, (guint8 *)&cs->cs_ip, 0, IP_HDR_LEN);
tvb_memcpy(tvb, (guint8 *)&cs->cs_tcp, ihl, TCP_HDR_LEN);
- if (ihl > IP_HDR_LEN)
+ if(ihl > IP_HDR_LEN)
tvb_memcpy(tvb, cs->cs_ipopt, sizeof(iphdr_type), ihl - IP_HDR_LEN);
- if (TCP_OFFSET(&(cs->cs_tcp)) > 5)
+ if(TCP_OFFSET(&(cs->cs_tcp)) > 5)
tvb_memcpy(tvb, cs->cs_tcpopt, ihl + sizeof(tcphdr_type),
(TCP_OFFSET(&(cs->cs_tcp)) - 5) * 4);
return;
}
-/* Wraper for in_cksum function */
+/* Wrapper for in_cksum function */
static guint16
ip_csum(const guint8 * ptr, guint32 len)
{
- vec_t cksum_vec[1];
+ vec_t cksum_vec[1];
- cksum_vec[0].ptr = ptr;
- cksum_vec[0].len = len;
- return in_cksum(&cksum_vec[0], 1);
+ cksum_vec[0].ptr = ptr;
+ cksum_vec[0].len = len;
+ return in_cksum(&cksum_vec[0], 1);
}