Maintain separate "discard compressed frames" state per connection.

Put the array of connection states into the per-direction state
structure; its size is fixed, as the connection number field size is 1
byte.  Get rid of the "rslot_limit" member, as the number is fixed.

Get rid of the per-state "next" pointer, as it's unused.

Process uncompressed frames even if VJ decompression is turned off, and
even if the "discard compressed frames" flag is set on the connection,
as there's no decompression to do.

If the full IP and TCP header isn't available in an uncompressed frame,
discard subsequent compressed frames.

Only use the "discard compressed frames" flag on the first pass through
the capture; on subsequent passes, the presence of an "uncompressed
header" item attached to the frame indicates whether we could decompress
it or not (the "discard compressed frames" flag would merely indicate
the *last* state it had for that connection, which might not have been
the state at the time we saw that frame).

svn path=/trunk/; revision=5520
This commit is contained in:
Guy Harris 2002-05-22 09:49:28 +00:00
parent 97a7ae2cba
commit bd8337321a
1 changed files with 210 additions and 234 deletions

View File

@ -1,7 +1,7 @@
/* packet-vj.c /* packet-vj.c
* Routines for Van Jacobson header decompression. * Routines for Van Jacobson header decompression.
* *
* $Id: packet-vj.c,v 1.9 2002/05/20 00:56:30 guy Exp $ * $Id: packet-vj.c,v 1.10 2002/05/22 09:49:28 guy Exp $
* *
* Ethereal - Network traffic analyzer * Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com> * By Gerald Combs <gerald@ethereal.com>
@ -84,6 +84,7 @@
#define IP_HDR_LEN 20 /* Minimum IP header length */ #define IP_HDR_LEN 20 /* Minimum IP header length */
#define IP_HDR_LEN_MASK 0x0f /* Mask for header length field */ #define IP_HDR_LEN_MASK 0x0f /* Mask for header length field */
#define IP_MAX_OPT_LEN 44 /* Max length of IP options */ #define IP_MAX_OPT_LEN 44 /* Max length of IP options */
#define TCP_FIELD_HDR_LEN 12 /* Data offset field in TCP hdr */
#define TCP_HDR_LEN 20 /* Minimum TCP header length */ #define TCP_HDR_LEN 20 /* Minimum TCP header length */
#define TCP_MAX_OPT_LEN 44 /* Max length of TCP options */ #define TCP_MAX_OPT_LEN 44 /* Max length of TCP options */
#define TCP_SIMUL_CONV_MAX 256 /* Max number of simul. TCP conversations */ #define TCP_SIMUL_CONV_MAX 256 /* Max number of simul. TCP conversations */
@ -146,20 +147,18 @@ typedef struct {
/* State per active tcp conversation */ /* State per active tcp conversation */
typedef struct cstate { typedef struct cstate {
struct cstate *next; /* next in ring (xmit) */
iphdr_type cs_ip; iphdr_type cs_ip;
tcphdr_type cs_tcp; tcphdr_type cs_tcp;
guint8 cs_ipopt[IP_MAX_OPT_LEN]; guint8 cs_ipopt[IP_MAX_OPT_LEN];
guint8 cs_tcpopt[TCP_MAX_OPT_LEN]; guint8 cs_tcpopt[TCP_MAX_OPT_LEN];
guint32 flags;
#define SLF_TOSS 0x00000001 /* tossing rcvd frames until id received */
} cstate; } cstate;
/* All the state data for one serial line */ /* All the state data for one serial line */
typedef struct { typedef struct {
cstate *rstate; /* receive connection states (array)*/ cstate rstate[TCP_SIMUL_CONV_MAX]; /* receive connection states (array) */
guint8 rslot_limit; /* highest receive slot id */ guint8 recv_current; /* most recent rcvd id */
guint8 recv_current; /* most recent rcvd id */
guint8 flags;
#define SLF_TOSS 0x01 /* tossing rcvd frames until id received */
} slcompress; } slcompress;
/* Initialize the protocol and registered fields */ /* Initialize the protocol and registered fields */
@ -207,11 +206,6 @@ static int get_signed_delta(tvbuff_t *tvb, int *offsetp, int hf,
static guint16 ip_csum(const guint8 *ptr, guint32 len); static guint16 ip_csum(const guint8 *ptr, guint32 len);
static slcompress *slhc_init(void); static slcompress *slhc_init(void);
static void vj_init(void); static void vj_init(void);
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,
packet_info *pinfo, slcompress *comp);
static gint vjc_process(tvbuff_t *src_tvb, packet_info *pinfo, proto_tree *tree, static gint vjc_process(tvbuff_t *src_tvb, packet_info *pinfo, proto_tree *tree,
slcompress *comp); slcompress *comp);
static gint vjc_tvb_setup(tvbuff_t *src_tvb, tvbuff_t **dst_tvb, static gint vjc_tvb_setup(tvbuff_t *src_tvb, tvbuff_t **dst_tvb,
@ -224,8 +218,14 @@ dissect_vjuc(tvbuff_t *tvb, packet_info *pinfo, proto_tree * tree)
proto_item *ti; proto_item *ti;
proto_tree *vj_tree = NULL; proto_tree *vj_tree = NULL;
slcompress *comp; slcompress *comp;
int i;
gint conn_index; gint conn_index;
tvbuff_t *next_tvb = NULL; cstate *cs = NULL;
guint8 ihl;
guint8 thl;
guint8 *buffer;
tvbuff_t *next_tvb;
gint isize = tvb_length(tvb);
if(check_col(pinfo->cinfo, COL_PROTOCOL)) if(check_col(pinfo->cinfo, COL_PROTOCOL))
col_set_str(pinfo->cinfo, COL_INFO, "PPP VJ"); col_set_str(pinfo->cinfo, COL_INFO, "PPP VJ");
@ -236,50 +236,158 @@ dissect_vjuc(tvbuff_t *tvb, packet_info *pinfo, proto_tree * tree)
vj_tree = proto_item_add_subtree(ti, ett_vj); 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;
}
if(pinfo->p2p_dir == P2P_DIR_UNKNOWN) { if(pinfo->p2p_dir == P2P_DIR_UNKNOWN) {
/* Direction of the traffic unknown - can't decompress */ /* Direction of the traffic unknown - can't update state */
if(check_col(pinfo->cinfo, COL_INFO)) comp = NULL;
col_set_str(pinfo->cinfo, COL_INFO, "VJ uncompressed TCP (direction unknown)"); } else {
if(tree != NULL) /* Get state for that direction, if any */
call_dissector(data_handle, tvb, pinfo, vj_tree); comp = rx_tx_state[pinfo->p2p_dir];
return;
} }
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. */
conn_index = vjuc_check(tvb, pinfo, vj_tree, comp);
if(conn_index == VJ_ERROR)
return;
/* Set up tvb containing decompressed packet */
if(vjuc_tvb_setup(tvb, &next_tvb, pinfo, comp) == VJ_ERROR)
return;
/* /*
* No errors, so: * Check to make sure we can fetch the connection index.
* */
* if packet seen for first time update state; if(!tvb_bytes_exist(tvb, IP_FIELD_PROTOCOL, 1)) {
* call IP dissector. /*
* We don't. We can't even mark a connection as non-decompressable,
* as we don't know which connection this is. Mark them all as
* non-decompressable.
*/
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);
if(comp != NULL) {
for(i = 0; i < TCP_SIMUL_CONV_MAX; i++)
comp->rstate[i].flags |= SLF_TOSS;
}
return;
}
/* Get connection index */
conn_index = tvb_get_guint8(tvb, IP_FIELD_PROTOCOL);
if(tree != NULL)
proto_tree_add_uint(vj_tree, hf_vj_connection_number, tvb,
IP_FIELD_PROTOCOL, 1, conn_index);
/*
* Update the current connection, and get a pointer to its state.
*/
if(comp != NULL) {
comp->recv_current = conn_index;
cs = &comp->rstate[conn_index];
}
/* Get the IP header length */
ihl = tvb_get_guint8(tvb, 0) & IP_HDR_LEN_MASK;
ihl <<= 2;
/* Check IP header length */
if(ihl < IP_HDR_LEN) {
if(check_col(pinfo->cinfo, COL_INFO)) {
col_add_fstr(pinfo->cinfo, COL_INFO, "VJ uncompressed TCP (IP header length (%u) < %u)",
ihl, IP_HDR_LEN);
}
if(cs != NULL)
cs->flags |= SLF_TOSS;
return;
}
/* Make sure we have the full IP header */
if(isize < ihl) {
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);
if(cs != NULL)
cs->flags |= SLF_TOSS;
return;
}
if(check_col(pinfo->cinfo, COL_INFO))
col_set_str(pinfo->cinfo, COL_INFO, "VJ uncompressed TCP");
/*
* Copy packet data to a buffer, and replace the connection index with
* the protocol type (which is always TCP), to give the actual IP header.
*/
buffer = g_malloc(isize);
tvb_memcpy(tvb, buffer, 0, isize);
buffer[IP_FIELD_PROTOCOL] = IP_PROTO_TCP;
/* Check IP checksum */
if(ip_csum(buffer, ihl) != ZERO) {
/*
* Checksum invalid - don't update state, and don't decompress
* any subsequent compressed packets in this direction.
*/
if(cs != NULL)
cs->flags |= SLF_TOSS;
cs = NULL; /* disable state updates */
} else {
/* Do we have the TCP header length in the tvbuff? */
if(!tvb_bytes_exist(tvb, ihl + TCP_FIELD_HDR_LEN, 1)) {
/* We don't, so we can't provide enough data for decompression */
if(check_col(pinfo->cinfo, COL_INFO))
col_set_str(pinfo->cinfo, COL_INFO, "VJ uncompressed TCP (not enough data available)");
if(cs != NULL)
cs->flags |= SLF_TOSS;
cs = NULL; /* disable state updates */
} else {
/* Get the TCP header length */
thl = tvb_get_guint8(tvb, ihl + TCP_FIELD_HDR_LEN);
thl = ((thl & 0xf0) >> 4) * 4;
/* Check TCP header length */
if(thl < TCP_HDR_LEN) {
if(check_col(pinfo->cinfo, COL_INFO)) {
col_add_fstr(pinfo->cinfo, COL_INFO, "VJ uncompressed TCP (TCP header length (%u) < %u)",
thl, TCP_HDR_LEN);
}
if(cs != NULL)
cs->flags |= SLF_TOSS;
cs = NULL; /* disable state updates */
} else {
/* Make sure we have the full TCP header */
if(isize < thl) {
if(check_col(pinfo->cinfo, COL_INFO))
col_set_str(pinfo->cinfo, COL_INFO, "VJ uncompressed TCP (not enough data available)");
if(cs != NULL)
cs->flags |= SLF_TOSS;
cs = NULL; /* disable state updates */
}
}
}
}
/*
* If packet seen for first time, update state if we have state and can
* update it.
*/
if(!pinfo->fd->flags.visited) {
if(cs != NULL) {
cs->flags &= ~SLF_TOSS;
memcpy(&cs->cs_ip, &buffer[0], IP_HDR_LEN);
memcpy(&cs->cs_tcp, &buffer[ihl], TCP_HDR_LEN);
if(ihl > IP_HDR_LEN)
memcpy(cs->cs_ipopt, &buffer[sizeof(iphdr_type)], ihl - IP_HDR_LEN);
if(TCP_OFFSET(&(cs->cs_tcp)) > 5)
memcpy(cs->cs_tcpopt, &buffer[ihl + sizeof(tcphdr_type)],
(TCP_OFFSET(&(cs->cs_tcp)) - 5) * 4);
}
}
/*
* Set up tvbuff containing packet with protocol type.
* Neither header checksum is recalculated.
*/
next_tvb = tvb_new_real_data(buffer, isize, pntohs(&buffer[IP_FIELD_TOT_LEN]));
tvb_set_child_real_data_tvbuff(tvb, next_tvb);
add_new_data_source(pinfo->fd, next_tvb, "VJ Uncompressed");
/*
* Call IP dissector.
*/ */
if(!pinfo->fd->flags.visited)
vjuc_update_state(next_tvb, comp, conn_index);
call_dissector(ip_handle, next_tvb, pinfo, tree); call_dissector(ip_handle, next_tvb, pinfo, tree);
} }
@ -320,14 +428,7 @@ dissect_vjc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
return; return;
} }
if((comp = rx_tx_state[pinfo->p2p_dir]) == NULL) { comp = rx_tx_state[pinfo->p2p_dir];
/* 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;
}
/* Process the compressed data header */ /* Process the compressed data header */
if(vjc_process(tvb, pinfo, vj_tree, comp) == VJ_ERROR) if(vjc_process(tvb, pinfo, vj_tree, comp) == VJ_ERROR)
@ -429,19 +530,15 @@ vj_init(void)
{ {
gint i = ZERO; gint i = ZERO;
slcompress *pslc = NULL; slcompress *pslc = NULL;
cstate *pstate = NULL;
if(vj_header_memchunk != NULL) if(vj_header_memchunk != NULL)
g_mem_chunk_destroy(vj_header_memchunk); g_mem_chunk_destroy(vj_header_memchunk);
vj_header_memchunk = g_mem_chunk_new("vj header store", sizeof (vj_header_t), vj_header_memchunk = g_mem_chunk_new("vj header store", sizeof (vj_header_t),
sizeof (vj_header_t) * VJ_ATOM_COUNT, sizeof (vj_header_t) * VJ_ATOM_COUNT,
G_ALLOC_ONLY); G_ALLOC_ONLY);
for(i=0; i< RX_TX_STATE_COUNT; i++){ for(i = 0; i < RX_TX_STATE_COUNT; i++) {
if((pslc = rx_tx_state[i]) != NULL){ if((pslc = rx_tx_state[i]) != NULL)
if((pstate = pslc->rstate) != NULL)
g_free(pstate);
g_free(pslc); g_free(pslc);
}
rx_tx_state[i] = slhc_init(); rx_tx_state[i] = slhc_init();
} }
return; return;
@ -451,22 +548,19 @@ vj_init(void)
static slcompress * static slcompress *
slhc_init(void) slhc_init(void)
{ {
size_t rsize = TCP_SIMUL_CONV_MAX * sizeof(cstate);
slcompress *comp = g_malloc(sizeof(slcompress)); slcompress *comp = g_malloc(sizeof(slcompress));
int i;
if(comp != NULL) { memset(comp, ZERO, sizeof(slcompress));
memset(comp, ZERO, sizeof(slcompress));
if((comp->rstate = g_malloc(rsize)) == NULL) { /*
g_free(comp); * Initialize the state; there is no current connection, and
comp = NULL; * we have no header data for any of the connections, as we
} * haven't yet seen an uncompressed frame.
else { */
memset(comp->rstate, ZERO, rsize); comp->recv_current = TCP_SIMUL_CONV_MAX - 1;
comp->rslot_limit = TCP_SIMUL_CONV_MAX - 1; for (i = 0; i < TCP_SIMUL_CONV_MAX; i++)
comp->recv_current = TCP_SIMUL_CONV_MAX - 1; comp->rstate[i].flags |= SLF_TOSS;
comp->flags |= SLF_TOSS;
}
}
return comp; return comp;
} }
@ -491,7 +585,7 @@ vjc_tvb_setup(tvbuff_t *src_tvb,
hdr_buf = p_get_proto_data(pinfo->fd, proto_vj); hdr_buf = p_get_proto_data(pinfo->fd, proto_vj);
if(hdr_buf == NULL) { if(hdr_buf == NULL) {
if(check_col(pinfo->cinfo, COL_INFO)) if(check_col(pinfo->cinfo, COL_INFO))
col_set_str(pinfo->cinfo, COL_INFO, "VJ compressed TCP (decompressed data not available)"); col_set_str(pinfo->cinfo, COL_INFO, "VJ compressed TCP (previous data bad or missing)");
return VJ_ERROR; return VJ_ERROR;
} }
@ -529,13 +623,14 @@ vjc_process(tvbuff_t *src_tvb, packet_info *pinfo, proto_tree *tree,
slcompress *comp) slcompress *comp)
{ {
int offset = ZERO; int offset = ZERO;
int i;
gint changes; gint changes;
proto_item *ti; proto_item *ti;
proto_tree *changes_tree; proto_tree *changes_tree;
guint8 conn_index; guint8 conn_index;
cstate *cs; cstate *cs = NULL;
iphdr_type *ip; iphdr_type *ip = NULL;
tcphdr_type *thp; tcphdr_type *thp = NULL;
guint16 tcp_cksum; guint16 tcp_cksum;
gint hdrlen = ZERO; gint hdrlen = ZERO;
guint16 word; guint16 word;
@ -545,11 +640,17 @@ vjc_process(tvbuff_t *src_tvb, packet_info *pinfo, proto_tree *tree,
guint8 *data_ptr; guint8 *data_ptr;
if(tvb_length(src_tvb) < 3){ if(tvb_length(src_tvb) < 3){
/*
* We don't even have enough data for the change byte, so we can't
* determine which connection this is; mark all connections as
* non-decompressible.
*/
if(check_col(pinfo->cinfo, COL_INFO)) if(check_col(pinfo->cinfo, COL_INFO))
col_set_str(pinfo->cinfo, COL_INFO, "VJ compressed TCP (not enough data available)"); col_set_str(pinfo->cinfo, COL_INFO, "VJ compressed TCP (not enough data available)");
if(tree != NULL) if(tree != NULL)
call_dissector(data_handle, src_tvb, pinfo, tree); call_dissector(data_handle, src_tvb, pinfo, tree);
comp->flags |= SLF_TOSS; for(i = 0; i < TCP_SIMUL_CONV_MAX; i++)
comp->rstate[i].flags |= SLF_TOSS;
return VJ_ERROR; return VJ_ERROR;
} }
@ -605,39 +706,33 @@ vjc_process(tvbuff_t *src_tvb, packet_info *pinfo, proto_tree *tree,
proto_tree_add_uint(tree, hf_vj_connection_number, src_tvb, offset, 1, proto_tree_add_uint(tree, hf_vj_connection_number, src_tvb, offset, 1,
conn_index); conn_index);
offset++; 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; comp->recv_current = conn_index;
} }
else {
if(comp->flags & SLF_TOSS) { if(!pinfo->fd->flags.visited) {
if(check_col(pinfo->cinfo, COL_INFO)) /*
col_set_str(pinfo->cinfo, COL_INFO, "VJ compressed TCP (previous data bad)"); * This is the first time this frame has been seen, so we need
return VJ_ERROR; * state information to decompress it. If that information isn't
* available, don't use the state information, and don't update it,
* either.
*/
if(!(comp->rstate[comp->recv_current].flags & SLF_TOSS)) {
cs = &comp->rstate[comp->recv_current];
thp = &cs->cs_tcp;
ip = &cs->cs_ip;
} }
} }
cs = &comp->rstate[comp->recv_current];
thp = &cs->cs_tcp;
ip = &cs->cs_ip;
/* Build TCP and IP headers */ /* Build TCP and IP headers */
tcp_cksum = tvb_get_ntohs(src_tvb, offset); tcp_cksum = tvb_get_ntohs(src_tvb, offset);
if(tree != NULL) if(tree != NULL)
proto_tree_add_uint(tree, hf_vj_tcp_cksum, src_tvb, offset, 2, tcp_cksum); proto_tree_add_uint(tree, hf_vj_tcp_cksum, src_tvb, offset, 2, tcp_cksum);
if(!pinfo->fd->flags.visited) { if(cs != NULL) {
hdrlen = lo_nibble(ip->ihl_version) * 4 + TCP_OFFSET(thp) * 4; hdrlen = lo_nibble(ip->ihl_version) * 4 + TCP_OFFSET(thp) * 4;
thp->cksum = htons(tcp_cksum); thp->cksum = htons(tcp_cksum);
} }
offset += 2; offset += 2;
if(!pinfo->fd->flags.visited) { if(cs != NULL) {
if(changes & CHANGE_PUSH_BIT) if(changes & CHANGE_PUSH_BIT)
thp->flags |= TCP_PUSH_BIT; thp->flags |= TCP_PUSH_BIT;
else else
@ -647,40 +742,40 @@ vjc_process(tvbuff_t *src_tvb, packet_info *pinfo, proto_tree *tree,
/* Deal with special cases and normal deltas */ /* Deal with special cases and normal deltas */
switch(changes & SPECIALS_MASK){ switch(changes & SPECIALS_MASK){
case SPECIAL_I: /* Echoed terminal traffic */ case SPECIAL_I: /* Echoed terminal traffic */
if(!pinfo->fd->flags.visited) { if(cs != NULL) {
word = ntohs(ip->tot_len) - hdrlen; word = ntohs(ip->tot_len) - hdrlen;
thp->ack_seq = htonl(ntohl(thp->ack_seq) + word); thp->ack_seq = htonl(ntohl(thp->ack_seq) + word);
thp->seq = htonl(ntohl(thp->seq) + word); thp->seq = htonl(ntohl(thp->seq) + word);
} }
break; break;
case SPECIAL_D: /* Unidirectional data */ case SPECIAL_D: /* Unidirectional data */
if(!pinfo->fd->flags.visited) if(cs != NULL)
thp->seq = htonl(ntohl(thp->seq) + ntohs(ip->tot_len) - hdrlen); thp->seq = htonl(ntohl(thp->seq) + ntohs(ip->tot_len) - hdrlen);
break; break;
default: default:
if(changes & NEW_U){ if(changes & NEW_U){
delta = get_unsigned_delta(src_tvb, &offset, hf_vj_urp, tree); delta = get_unsigned_delta(src_tvb, &offset, hf_vj_urp, tree);
if(!pinfo->fd->flags.visited) { if(cs != NULL) {
thp->urg_ptr = delta; thp->urg_ptr = delta;
thp->flags |= TCP_URG_BIT; thp->flags |= TCP_URG_BIT;
} }
} else { } else {
if(!pinfo->fd->flags.visited) if(cs != NULL)
thp->flags &= ~TCP_URG_BIT; thp->flags &= ~TCP_URG_BIT;
} }
if(changes & NEW_W) { if(changes & NEW_W) {
delta = get_signed_delta(src_tvb, &offset, hf_vj_win_delta, tree); delta = get_signed_delta(src_tvb, &offset, hf_vj_win_delta, tree);
if(!pinfo->fd->flags.visited) if(cs != NULL)
thp->window = htons(ntohs(thp->window) + delta); thp->window = htons(ntohs(thp->window) + delta);
} }
if(changes & NEW_A) { if(changes & NEW_A) {
delta = get_unsigned_delta(src_tvb, &offset, hf_vj_ack_delta, tree); delta = get_unsigned_delta(src_tvb, &offset, hf_vj_ack_delta, tree);
if(!pinfo->fd->flags.visited) if(cs != NULL)
thp->ack_seq = htonl(ntohl(thp->ack_seq) + delta); thp->ack_seq = htonl(ntohl(thp->ack_seq) + delta);
} }
if(changes & NEW_S) { if(changes & NEW_S) {
delta = get_unsigned_delta(src_tvb, &offset, hf_vj_seq_delta, tree); delta = get_unsigned_delta(src_tvb, &offset, hf_vj_seq_delta, tree);
if(!pinfo->fd->flags.visited) if(cs != NULL)
thp->seq = htonl(ntohl(thp->seq) + delta); thp->seq = htonl(ntohl(thp->seq) + delta);
} }
break; break;
@ -689,7 +784,7 @@ vjc_process(tvbuff_t *src_tvb, packet_info *pinfo, proto_tree *tree,
delta = get_unsigned_delta(src_tvb, &offset, hf_vj_ip_id_delta, tree); delta = get_unsigned_delta(src_tvb, &offset, hf_vj_ip_id_delta, tree);
else else
delta = 1; delta = 1;
if(!pinfo->fd->flags.visited) if(cs != NULL)
ip->id = htons(ntohs(ip->id) + delta); ip->id = htons(ntohs(ip->id) + delta);
/* Compute IP packet length and the buffer length needed */ /* Compute IP packet length and the buffer length needed */
@ -701,11 +796,11 @@ vjc_process(tvbuff_t *src_tvb, packet_info *pinfo, proto_tree *tree,
*/ */
if(check_col(pinfo->cinfo, COL_INFO)) if(check_col(pinfo->cinfo, COL_INFO))
col_set_str(pinfo->cinfo, COL_INFO, "VJ compressed TCP (not enough data available)"); col_set_str(pinfo->cinfo, COL_INFO, "VJ compressed TCP (not enough data available)");
comp->flags |= SLF_TOSS; comp->rstate[comp->recv_current].flags |= SLF_TOSS;
return VJ_ERROR; return VJ_ERROR;
} }
if(!pinfo->fd->flags.visited) { if(cs != NULL) {
len += hdrlen; len += hdrlen;
ip->tot_len = htons(len); ip->tot_len = htons(len);
/* Compute IP check sum */ /* Compute IP check sum */
@ -783,125 +878,6 @@ get_signed_delta(tvbuff_t *tvb, int *offsetp, int hf, proto_tree *tree)
return del; return del;
} }
/* For VJ uncompressed packet check if it is malformed */
static gint
vjuc_check(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
slcompress *comp)
{
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;
return VJ_ERROR;
}
/* 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;
}
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;
}
/* Setup the decompressed packet tvb for VJ uncompressed packets */
static gint
vjuc_tvb_setup(tvbuff_t *tvb,
tvbuff_t **dst_tvb,
packet_info *pinfo,
slcompress *comp)
{
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;
ihl <<= 2;
/* Copy packet data to a buffer */
buffer = g_malloc(isize);
tvb_memcpy(tvb, buffer, 0, isize);
buffer[IP_FIELD_PROTOCOL] = IP_PROTO_TCP;
/* Compute checksum */
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, 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;
}
/* For VJ uncompressed packets update the decompressor state */
static void
vjuc_update_state(tvbuff_t *tvb, slcompress *comp, guint8 index)
{
cstate *cs = NULL;
guint8 ihl = ZERO;
g_assert(comp);
g_assert(tvb);
/* Get the IP header length */
ihl = tvb_get_guint8(tvb, 0) & IP_HDR_LEN_MASK;
ihl <<= 2;
/* Update local state */
cs = &comp->rstate[comp->recv_current = 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)
tvb_memcpy(tvb, cs->cs_ipopt, sizeof(iphdr_type), ihl - IP_HDR_LEN);
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;
}
/* Wrapper for in_cksum function */ /* Wrapper for in_cksum function */
static guint16 static guint16
ip_csum(const guint8 * ptr, guint32 len) ip_csum(const guint8 * ptr, guint32 len)