aboutsummaryrefslogtreecommitdiffstats
path: root/packet-vj.c
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2002-05-20 00:56:30 +0000
committerGuy Harris <guy@alum.mit.edu>2002-05-20 00:56:30 +0000
commit44580a93ca4c8c323b99200deac2b64c9033d96e (patch)
tree262c2e68a5099d8676886903d562b3f8b72c5efe /packet-vj.c
parent6519b11bcbc4eb20daf4a77b30566f1ceabe6f50 (diff)
Don't include the FCS in the tvbuff handed to "dissect_ppp_common()", so
that it's not included in the tvbuff handed to subdissectors. Use that tvbuff to compute the FCS. Properly handle the FCS in frames that don't include all the captured data. In VJ-compressed packets, put the VJ compression information into the protocol tree, and set the Protocol and Info columns, and don't worry about the CRC - as per the above, it's no longer in the tvbuff (and never *was* in the tvbuff in some cases). Also, clean up some other stuff in the VJ dissector. svn path=/trunk/; revision=5510
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);
}