diff options
author | Guy Harris <guy@alum.mit.edu> | 2001-12-19 21:14:49 +0000 |
---|---|---|
committer | Guy Harris <guy@alum.mit.edu> | 2001-12-19 21:14:49 +0000 |
commit | 3624071a7987d35d2fc80e8b56122df0b913574e (patch) | |
tree | f0190badc5de82e19f5f2cc644d1709724806240 /packet-vj.c | |
parent | b2e832d9cacca07096a6c8f00d6667373a7bdf49 (diff) |
Van Jacobson decompression support for PPP, from Irfan Khan.
svn path=/trunk/; revision=4427
Diffstat (limited to 'packet-vj.c')
-rw-r--r-- | packet-vj.c | 711 |
1 files changed, 711 insertions, 0 deletions
diff --git a/packet-vj.c b/packet-vj.c new file mode 100644 index 0000000000..fd2c75ee66 --- /dev/null +++ b/packet-vj.c @@ -0,0 +1,711 @@ +/* packet-vj.c + * Routines for Van Jacobson header decompression. + * + * $Id: packet-vj.c,v 1.1 2001/12/19 21:14:49 guy Exp $ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs <gerald@ethereal.com> + * + * This file created by Irfan Khan <ikhan@qualcomm.com> + * Copyright (c) 2001 by QUALCOMM, Incorporated. + * All Rights reserved. + * + * Routines to compress and uncompress tcp packets (for transmission + * over low speed serial lines). + * + * Copyright (c) 1989 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: + * - Initial distribution. + * + * + * modified for KA9Q Internet Software Package by + * Katie Stevens (dkstevens@ucdavis.edu) + * University of California, Davis + * Computing Services + * - 01-31-90 initial adaptation (from 1.19) + * PPP.05 02-15-90 [ks] + * PPP.08 05-02-90 [ks] use PPP protocol field to signal compression + * PPP.15 09-90 [ks] improve mbuf handling + * PPP.16 11-02 [karn] substantially rewritten to use NOS facilities + * + * - Feb 1991 Bill_Simpson@um.cc.umich.edu + * variable number of conversation slots + * allow zero or one slots + * separate routines + * status display + * - Jul 1994 Dmitry Gorodchanin + * Fixes for memory leaks. + * - Oct 1994 Dmitry Gorodchanin + * Modularization. + * - Jan 1995 Bjorn Ekwall + * Use ip_fast_csum from ip.h + * - July 1995 Christos A. Polyzols + * Spotted bug in tcp option checking + * - Sep 2001 Irfan Khan + * Rewrite to make the code work for ethereal. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif + +#include <glib.h> +#include <string.h> +#include "packet.h" +#include "packet-ppp.h" +#include "ppptypes.h" +#include "in_cksum.h" +#include "epan/tvbuff.h" + +/* Define relevant IP/TCP parameters */ +#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_PUSH_BIT 0x10 /* TCP push bit */ +#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 */ + +/* 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 + +/* reserved, special-case values of above */ +#define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */ +#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U)/* unidirectional data */ +#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U) + +/* Function return values */ +#define VJ_OK 0 +#define VJ_ERROR -1 + +/* Define for 0 */ +#define ZERO 0 + +/* Two byte CRC */ +#define CRC_LEN sizeof(guint16) + +/* VJ Mem Chunk defines */ +#define VJ_ATOM_SIZE 129 /* Max IP hdr(64)+Max TCP hdr(64)+offset byte */ +#define VJ_ATOM_COUNT 250 /* Number of Atoms per block */ + +/* IP and TCP header types */ +typedef struct { +#if BYTE_ORDER == LITTLE_ENDIAN + guint8 ihl:4, + version:4; +#else + guint8 version:4, + ihl:4; +#endif + guint8 tos; + guint16 tot_len; + guint16 id; + guint16 frag_off; + guint8 ttl; + guint8 proto; + guint16 cksum; + guint32 src; + guint32 dst; +} iphdr_type; + +typedef struct { + guint16 srcport; + guint16 dstport; + guint32 seq; + guint32 ack_seq; +#if BYTE_ORDER == LITTLE_ENDIAN + guint16 res1:4, + doff:4, + fin:1, + syn:1, + rst:1, + psh:1, + ack:1, + urg:1, + ece:1, + cwr:1; +#else + guint16 doff:4, + res1:4, + cwr:1, + ece:1, + urg:1, + ack:1, + psh:1, + rst:1, + syn:1, + fin:1; +#endif + guint16 window; + guint16 cksum; + guint16 urg_ptr; +} tcphdr_type; + + +/* State per active tcp conversation */ +typedef struct cstate { + struct cstate *next; /* next in ring (xmit) */ + iphdr_type cs_ip; + tcphdr_type cs_tcp; + guint8 cs_ipopt[IP_MAX_OPT_LEN]; + guint8 cs_tcpopt[TCP_MAX_OPT_LEN]; +} cstate; + +/* All the state data for one serial line */ +typedef struct { + cstate *rstate; /* receive connection states (array)*/ + guint8 rslot_limit; /* highest receive slot id */ + guint8 recv_current; /* most recent rcvd id */ + guint8 flags; +#define SLF_TOSS 0x01 /* tossing rcvd frames until id received */ +} slcompress; + +/* Initialize the protocol and registered fields */ +static int proto_vj = -1; + +/* Protocol handles */ +static dissector_handle_t vjc_handle; +static dissector_handle_t vjuc_handle; +static dissector_handle_t data_handle; + +/* State repository (Full Duplex) */ +#define RX_TX_STATE_COUNT 2 +static slcompress *rx_tx_state[RX_TX_STATE_COUNT] = {NULL, NULL}; + +/* Mem Chunks for storing decompressed headers */ +static GMemChunk *vj_header_memchunk = NULL; + +/* Function prototypes */ +static void decodes(tvbuff_t *tvb, guint32 *offset, gint16 *val); +static void decodel(tvbuff_t *tvb, guint32 *offset, gint32 *val); +static guint16 ip_csum(const guint8 *ptr, guint32 len); +static slcompress *slhc_init(gint rslots); +static void vj_init(void); +static void vj_display_pkt(tvbuff_t *parent_tvb, tvbuff_t *child_tvb, + packet_info *pinfo, proto_tree *tree); +static gint vjuc_check(tvbuff_t *tvb, 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); +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); + +/* Dissector for VJ Uncompressed packets */ +static void +dissect_vjuc(tvbuff_t *tvb, packet_info *pinfo, proto_tree * tree) +{ + tvbuff_t *next_tvb = NULL; + tvbuff_t *data_tvb = NULL; + slcompress *comp = NULL; + gint conn_index = ZERO; + gint err = VJ_OK; + + /* 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; + + /* Check if packet malformed. */ + if(err == VJ_OK) + err = conn_index = vjuc_check(tvb, comp); + + /* Set up tvb containing decompressed packet */ + if(err != VJ_ERROR) + err = vjuc_tvb_setup(tvb, &next_tvb, comp); + + /* If packet seen for first time update state */ + if(pinfo->fd->flags.visited != 1 && err == VJ_OK) + vjuc_update_state(next_tvb, comp, conn_index); + + /* If no errors call IP dissector else dissect as data. */ + if(err == VJ_OK) + vj_display_pkt(tvb, next_tvb, pinfo, tree); + else { + data_tvb = tvb_new_subset(tvb, 0, -1, -1); + call_dissector(data_handle, data_tvb, pinfo, tree); + } +} + +/* Dissector for VJ Compressed packets */ +static void +dissect_vjc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + tvbuff_t *next_tvb = NULL; + tvbuff_t *data_tvb = NULL; + slcompress *comp = NULL; + gint err = VJ_OK; + + /* 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; + + /* Check if packet malformed. */ + if(err != VJ_ERROR) + err = vjc_check(tvb, comp); + + /* 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); + } + + /* Set up tvb containing decompressed packet */ + if(err == VJ_OK) + err = vjc_tvb_setup(tvb, &next_tvb, pinfo->fd); + + /* If no errors call IP dissector else dissect as data */ + if(err == VJ_OK) + vj_display_pkt(tvb, next_tvb, pinfo, tree); + else { + data_tvb = tvb_new_subset(tvb, 0, -1, -1); + call_dissector(data_handle, data_tvb, pinfo, tree); + } +} + +/* Registeration functions for dissectors */ +void +proto_register_vj(void) +{ + proto_vj = proto_register_protocol("PPP VJ Compression", "PPP VJ", "vj"); + register_init_routine(&vj_init); + + vjc_handle = create_dissector_handle(dissect_vjc, proto_vj); + vjuc_handle = create_dissector_handle(dissect_vjuc, proto_vj); + +} + +void +proto_reg_handoff_vj(void) +{ + dissector_add("ppp.protocol", PPP_VJC_COMP, vjc_handle); + dissector_add("ppp.protocol", PPP_VJC_UNCOMP, vjuc_handle); + + data_handle = find_dissector("data"); +} + +/* Function to setup decompressed packet display */ +static void +vj_display_pkt(tvbuff_t *parent_tvb, + tvbuff_t *child_tvb, + packet_info *pinfo, + proto_tree *tree) +{ + dissector_handle_t ip_handle = find_dissector("ip"); + frame_data *fd = pinfo->fd; + tvbuff_t *data_tvb = NULL; + + g_assert(parent_tvb); + g_assert(child_tvb); + g_assert(fd); + + if (ip_handle == NULL) { + data_tvb = tvb_new_subset(child_tvb, 0, -1, -1); + call_dissector(data_handle, data_tvb, pinfo, tree); + } + else { + tvb_set_child_real_data_tvbuff(parent_tvb, child_tvb); + fd->data_src = g_slist_append(fd->data_src, child_tvb); + SET_ADDRESS(&pinfo->net_src, + AT_IPv4, + IP_ADDR_SIZE, + tvb_get_ptr(child_tvb, IP_FIELD_SRC, IP_ADDR_SIZE)); + SET_ADDRESS(&pinfo->src, + AT_IPv4, + IP_ADDR_SIZE, + tvb_get_ptr(child_tvb, IP_FIELD_SRC, IP_ADDR_SIZE)); + SET_ADDRESS(&pinfo->net_dst, + AT_IPv4, + IP_ADDR_SIZE, + tvb_get_ptr(child_tvb, IP_FIELD_DST, IP_ADDR_SIZE)); + SET_ADDRESS(&pinfo->dst, + AT_IPv4, + IP_ADDR_SIZE, + tvb_get_ptr(child_tvb, IP_FIELD_DST, IP_ADDR_SIZE)); + call_dissector(ip_handle, child_tvb, pinfo, tree); + } + return; +} + +/* Initialization function */ +static void +vj_init(void) +{ + gint i = ZERO; + slcompress *pslc = NULL; + cstate *pstate = NULL; + + if(vj_header_memchunk != NULL) + g_mem_chunk_destroy(vj_header_memchunk); + vj_header_memchunk = g_mem_chunk_new("vj header store", VJ_ATOM_SIZE, + VJ_ATOM_SIZE * VJ_ATOM_COUNT, + G_ALLOC_AND_FREE); + for(i=0; i< RX_TX_STATE_COUNT; i++){ + if((pslc = rx_tx_state[i]) != NULL){ + if((pstate = pslc->rstate) != NULL) + g_free(pstate); + g_free(pslc); + } + rx_tx_state[i] = slhc_init(TCP_SIMUL_CONV); + } + return; +} + +/* Initialization routine for VJ decompression */ +static slcompress * +slhc_init(gint rslots) +{ + size_t rsize = rslots * sizeof(cstate); + slcompress *comp = g_malloc(sizeof(slcompress)); + + if(rslots < ZERO || rslots > TCP_SIMUL_CONV_MAX) + return NULL; + + if (comp != NULL) { + memset(comp, ZERO, sizeof(slcompress)); + if ((comp->rstate = g_malloc(rsize)) == NULL) { + g_free(comp); + comp = NULL; + } + else { + memset(comp->rstate, ZERO, rsize); + comp->rslot_limit = rslots - 1; + comp->recv_current = TCP_SIMUL_CONV_MAX - 1; + comp->flags |= SLF_TOSS; + } + } + return comp; +} + +/* Setup the decompressed packet tvb for VJ compressed packets */ +static gint +vjc_tvb_setup(tvbuff_t *src_tvb, + tvbuff_t **dst_tvb, + frame_data * fd) +{ + tvbuff_t *orig_tvb = NULL; + guint8 *hdr_buf = NULL; + guint8 *pbuf = NULL; + gint hdr_len = ZERO; + gint buf_len = ZERO; + guint8 offset = ZERO; + + 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) + return VJ_ERROR; + + /* First byte contains data offset in the tvbuff */ + offset = *hdr_buf++; + + /* Copy header and form tvb */ + hdr_len = ((iphdr_type *)hdr_buf)->ihl * 4; + hdr_len += ((tcphdr_type *)(hdr_buf + hdr_len))->doff * 4; + buf_len = tvb_length(src_tvb) + hdr_len - offset; + pbuf = g_malloc(buf_len); + memcpy(pbuf, hdr_buf, 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, "VJ Decompressed"); + return VJ_OK; +} + +/* For VJ compressed packets update the decompressor state */ +static gint +vjc_update_state(tvbuff_t *src_tvb, slcompress *comp, frame_data *fd) +{ + guint8 *buf_hdr = NULL; + 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); + + /* Read the change byte */ + changes = tvb_get_guint8(src_tvb, offset++); + if(changes & NEW_C) + offset++; + + /* Build TCP and IP headers */ + hdrlen = ip->ihl * 4 + thp->doff * 4; + thp->cksum = htons((tvb_get_guint8(src_tvb, offset++) << 8) | + tvb_get_guint8(src_tvb, offset++)); + thp->psh = (changes & TCP_PUSH_BIT) ? 1 : 0; + + /* 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; + case SPECIAL_D: /* Unidirectional data */ + 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->urg = 1; + } + else + thp->urg = 0; + 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; + } + if(changes & NEW_I) + decodes(src_tvb, &offset, &ip->id); + 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) { + comp->flags |= SLF_TOSS; + return VJ_ERROR; + } + len += hdrlen; + ip->tot_len = htons(len); + ip->cksum = ZERO; + + /* Store the reconstructed header in frame data area */ + buf_hdr = g_mem_chunk_alloc(vj_header_memchunk); + buf_hdr[0] = offset; /* Offset in tvbuff is also stored */ + memcpy((buf_hdr + sizeof(guint8)), ip, IP_HDR_LEN); + /* Compute IP check sum */ + ((iphdr_type *)(buf_hdr + sizeof(guint8)))->cksum = + ip_csum((buf_hdr + sizeof(guint8)), ip->ihl * 4); + if(ip->ihl > 5) + memcpy((buf_hdr + sizeof(guint8) + IP_HDR_LEN), + cs->cs_ipopt, + (ip->ihl - 5) * 4); + memcpy((buf_hdr + sizeof(guint8) + (ip->ihl * 4)), thp, TCP_HDR_LEN); + if(thp->doff > 5) + memcpy((buf_hdr + sizeof(guint8) + (ip->ihl *4) + TCP_HDR_LEN), + cs->cs_tcpopt, + (thp->doff - 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; + } + + /* Read the change byte */ + changes = tvb_get_guint8(src_tvb, offset++); + + 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) +{ + gint del = tvb_get_guint8(tvb, (*offset)++); + if(del == ZERO){ + del = tvb_get_ntohs(tvb, *offset); + *offset= *offset + 2; + } + *val = htonl(ntohl(*val) + del); + return; +} + +/* Decode the delta of a 16 bit header field */ +static void +decodes(tvbuff_t *tvb, guint32* offset, gint16 *val) +{ + gint del = tvb_get_guint8(tvb, (*offset)++); + if(del == ZERO){ + del = tvb_get_ntohs(tvb, *offset); + *offset= *offset + 2; + } + *val = htons(ntohs(*val) + del); + return; +} + +/* For VJ uncompressed packet check if it is malformed */ +static gint +vjuc_check(tvbuff_t *tvb, slcompress *comp) +{ + guint8 ihl = ZERO; + gint index = ZERO; + + g_assert(comp); + g_assert(tvb); + + if(tvb_length(tvb) < IP_HDR_LEN) { + comp->flags |= SLF_TOSS; + index = 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); + + /* Check connection number and IP header length field */ + if(ihl < IP_HDR_LEN || index > comp->rslot_limit) { + comp->flags |= SLF_TOSS; + index = 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, + slcompress *comp) +{ + guint8 ihl = ZERO; + guint8 index = ZERO; + gint isize = tvb_length(tvb); + guint8 *buffer = NULL; + tvbuff_t *orig_tvb = NULL; + gint orig_offset = 0; + + g_assert(comp); + g_assert(tvb); + + /* 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_PROTOCOL_TCP; + + /* Compute checksum */ + if (ip_csum(buffer, ihl) != ZERO) { + g_free(buffer); + comp->flags |= SLF_TOSS; + return VJ_ERROR; + } + + /* + * Form the new tvbuff. + * Neither header checksum is recalculated + */ + *dst_tvb = tvb_new_real_data(buffer, isize, isize, "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; + gint isize = tvb_length(tvb); + + 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 (cs->cs_tcp.doff > 5) + tvb_memcpy(tvb, cs->cs_tcpopt, ihl + sizeof(tcphdr_type), + (cs->cs_tcp.doff - 5) * 4); + return; +} + +/* Wraper for in_cksum function */ +static guint16 +ip_csum(const guint8 * ptr, guint32 len) +{ + vec_t cksum_vec[1]; + + cksum_vec[0].ptr = ptr; + cksum_vec[0].len = len; + return in_cksum(&cksum_vec[0], 1); +} |