2 * Routines for Van Jacobson header decompression.
4 * $Id: packet-vj.c,v 1.17 2003/08/26 05:52:53 guy Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@ethereal.com>
9 * This file created by Irfan Khan <ikhan@qualcomm.com>
10 * Copyright (c) 2001 by QUALCOMM, Incorporated.
11 * All Rights reserved.
13 * Routines to compress and uncompress TCP packets (for transmission
14 * over low speed serial lines).
16 * Copyright (c) 1989 Regents of the University of California.
17 * All rights reserved.
19 * Redistribution and use in source and binary forms are permitted
20 * provided that the above copyright notice and this paragraph are
21 * duplicated in all such forms and that any documentation,
22 * advertising materials, and other materials related to such
23 * distribution and use acknowledge that the software was developed
24 * by the University of California, Berkeley. The name of the
25 * University may not be used to endorse or promote products derived
26 * from this software without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
28 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
29 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
31 * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
32 * - Initial distribution.
35 * modified for KA9Q Internet Software Package by
36 * Katie Stevens (dkstevens@ucdavis.edu)
37 * University of California, Davis
39 * - 01-31-90 initial adaptation (from 1.19)
40 * PPP.05 02-15-90 [ks]
41 * PPP.08 05-02-90 [ks] use PPP protocol field to signal compression
42 * PPP.15 09-90 [ks] improve mbuf handling
43 * PPP.16 11-02 [karn] substantially rewritten to use NOS facilities
45 * - Feb 1991 Bill_Simpson@um.cc.umich.edu
46 * variable number of conversation slots
47 * allow zero or one slots
50 * - Jul 1994 Dmitry Gorodchanin
51 * Fixes for memory leaks.
52 * - Oct 1994 Dmitry Gorodchanin
54 * - Jan 1995 Bjorn Ekwall
55 * Use ip_fast_csum from ip.h
56 * - July 1995 Christos A. Polyzols
57 * Spotted bug in tcp option checking
58 * - Sep 2001 Irfan Khan
59 * Rewrite to make the code work for ethereal.
68 #include <epan/packet.h>
70 #include "packet-ppp.h"
75 /* Define relevant IP/TCP parameters */
76 #define IP_FIELD_TOT_LEN 2 /* Total length field in IP hdr */
77 #define IP_FIELD_PROTOCOL 9 /* Protocol field byte in IP hdr */
78 #define IP_ADDR_SIZE 4 /* Size in bytes of IPv4 address */
79 #define IP_FIELD_SRC 12 /* Byte 12 in IP hdr - src address */
80 #define IP_FIELD_DST 16 /* Byte 16 in IP hdr - dst address */
81 #define IP_HDR_LEN 20 /* Minimum IP header length */
82 #define IP_HDR_LEN_MASK 0x0f /* Mask for header length field */
83 #define IP_MAX_OPT_LEN 44 /* Max length of IP options */
84 #define TCP_FIELD_HDR_LEN 12 /* Data offset field in TCP hdr */
85 #define TCP_HDR_LEN 20 /* Minimum TCP header length */
86 #define TCP_MAX_OPT_LEN 44 /* Max length of TCP options */
87 #define TCP_SIMUL_CONV_MAX 256 /* Max number of simul. TCP conversations */
88 #define TCP_PUSH_BIT 0x08 /* TCP push bit */
89 #define TCP_URG_BIT 0x20 /* TCP urgent bit */
91 /* Bits in first octet of compressed packet */
92 /* flag bits for what changed in a packet */
93 #define NEW_C 0x40 /* Connection number changed */
94 #define NEW_I 0x20 /* IP sequence number change by value != 1 */
95 #define CHANGE_PUSH_BIT 0x10 /* TCP push bit set */
96 #define NEW_S 0x08 /* Sequence number changed */
97 #define NEW_A 0x04 /* Ack sequence number changed */
98 #define NEW_W 0x02 /* Window changed */
99 #define NEW_U 0x01 /* Urgent pointer present */
101 /* reserved, special-case values of above */
102 #define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */
103 #define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U)/* unidirectional data */
104 #define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U)
106 /* Function return values */
113 /* VJ Mem Chunk defines */
114 #define VJ_DATA_SIZE 128 /* Max IP hdr(64)+Max TCP hdr(64) */
115 #define VJ_ATOM_COUNT 250 /* Number of Atoms per block */
117 /* IP and TCP header types */
143 #define TCP_OFFSET(th) (((th)->off_x2 & 0xf0) >> 4)
145 /* State per active tcp conversation */
146 typedef struct cstate {
149 guint8 cs_ipopt[IP_MAX_OPT_LEN];
150 guint8 cs_tcpopt[TCP_MAX_OPT_LEN];
152 #define SLF_TOSS 0x00000001 /* tossing rcvd frames until id received */
155 /* All the state data for one serial line */
157 cstate rstate[TCP_SIMUL_CONV_MAX]; /* receive connection states (array) */
158 guint8 recv_current; /* most recent rcvd id */
161 /* Initialize the protocol and registered fields */
162 static int proto_vj = -1;
164 static int hf_vj_change_mask = -1;
165 static int hf_vj_change_mask_c = -1;
166 static int hf_vj_change_mask_i = -1;
167 static int hf_vj_change_mask_p = -1;
168 static int hf_vj_change_mask_s = -1;
169 static int hf_vj_change_mask_a = -1;
170 static int hf_vj_change_mask_w = -1;
171 static int hf_vj_change_mask_u = -1;
172 static int hf_vj_connection_number = -1;
173 static int hf_vj_tcp_cksum = -1;
174 static int hf_vj_urp = -1;
175 static int hf_vj_win_delta = -1;
176 static int hf_vj_ack_delta = -1;
177 static int hf_vj_seq_delta = -1;
178 static int hf_vj_ip_id_delta = -1;
180 static gint ett_vj = -1;
181 static gint ett_vj_changes = -1;
183 /* Protocol handles */
184 static dissector_handle_t ip_handle;
185 static dissector_handle_t data_handle;
187 /* State repository (Full Duplex) */
188 #define RX_TX_STATE_COUNT 2
189 static slcompress *rx_tx_state[RX_TX_STATE_COUNT] = {NULL, NULL};
191 /* Mem Chunks for storing decompressed headers */
192 static GMemChunk *vj_header_memchunk = NULL;
194 int offset; /* uppermost bit is "can't dissect" flag */
195 guint8 data[VJ_DATA_SIZE];
198 /* Function prototypes */
199 static int get_unsigned_delta(tvbuff_t *tvb, int *offsetp, int hf,
201 static int get_signed_delta(tvbuff_t *tvb, int *offsetp, int hf,
203 static guint16 ip_csum(const guint8 *ptr, guint32 len);
204 static slcompress *slhc_init(void);
205 static void vj_init(void);
206 static gint vjc_process(tvbuff_t *src_tvb, packet_info *pinfo, proto_tree *tree,
208 static gint vjc_tvb_setup(tvbuff_t *src_tvb, tvbuff_t **dst_tvb,
211 /* Dissector for VJ Uncompressed packets */
213 dissect_vjuc(tvbuff_t *tvb, packet_info *pinfo, proto_tree * tree)
216 proto_tree *vj_tree = NULL;
225 gint isize = tvb_length(tvb);
228 if(check_col(pinfo->cinfo, COL_PROTOCOL))
229 col_set_str(pinfo->cinfo, COL_INFO, "PPP VJ");
232 ti = proto_tree_add_protocol_format(tree, proto_vj, tvb, 0, -1,
233 "PPP VJ Compression: Uncompressed data");
234 vj_tree = proto_item_add_subtree(ti, ett_vj);
237 if(pinfo->p2p_dir == P2P_DIR_UNKNOWN) {
238 /* Direction of the traffic unknown - can't update state */
241 /* Get state for that direction */
242 comp = rx_tx_state[pinfo->p2p_dir];
246 * Check to make sure we can fetch the connection index.
248 if(!tvb_bytes_exist(tvb, IP_FIELD_PROTOCOL, 1)) {
250 * We don't. We can't even mark a connection as non-decompressable,
251 * as we don't know which connection this is. Mark them all as
252 * non-decompressable.
254 if(check_col(pinfo->cinfo, COL_INFO))
255 col_set_str(pinfo->cinfo, COL_INFO, "VJ uncompressed TCP (not enough data available)");
257 call_dissector(data_handle, tvb, pinfo, tree);
259 for(i = 0; i < TCP_SIMUL_CONV_MAX; i++)
260 comp->rstate[i].flags |= SLF_TOSS;
265 /* Get connection index */
266 conn_index = tvb_get_guint8(tvb, IP_FIELD_PROTOCOL);
268 proto_tree_add_uint(vj_tree, hf_vj_connection_number, tvb,
269 IP_FIELD_PROTOCOL, 1, conn_index);
272 * Update the current connection, and get a pointer to its state.
275 comp->recv_current = conn_index;
276 cs = &comp->rstate[conn_index];
279 /* Get the IP header length */
280 ihl = tvb_get_guint8(tvb, 0) & IP_HDR_LEN_MASK;
283 /* Check IP header length */
284 if(ihl < IP_HDR_LEN) {
285 if(check_col(pinfo->cinfo, COL_INFO)) {
286 col_add_fstr(pinfo->cinfo, COL_INFO, "VJ uncompressed TCP (IP header length (%u) < %u)",
290 cs->flags |= SLF_TOSS;
294 /* Make sure we have the full IP header */
296 if(check_col(pinfo->cinfo, COL_INFO))
297 col_set_str(pinfo->cinfo, COL_INFO, "VJ uncompressed TCP (not enough data available)");
299 call_dissector(data_handle, tvb, pinfo, tree);
301 cs->flags |= SLF_TOSS;
305 if(check_col(pinfo->cinfo, COL_INFO))
306 col_set_str(pinfo->cinfo, COL_INFO, "VJ uncompressed TCP");
309 * Copy packet data to a buffer, and replace the connection index with
310 * the protocol type (which is always TCP), to give the actual IP header.
312 buffer = g_malloc(isize);
313 tvb_memcpy(tvb, buffer, 0, isize);
314 buffer[IP_FIELD_PROTOCOL] = IP_PROTO_TCP;
316 /* Check IP checksum */
317 if(ip_csum(buffer, ihl) != ZERO) {
319 * Checksum invalid - don't update state, and don't decompress
320 * any subsequent compressed packets in this direction.
323 cs->flags |= SLF_TOSS;
324 cs = NULL; /* disable state updates */
326 /* Do we have the TCP header length in the tvbuff? */
327 if(!tvb_bytes_exist(tvb, ihl + TCP_FIELD_HDR_LEN, 1)) {
328 /* We don't, so we can't provide enough data for decompression */
329 if(check_col(pinfo->cinfo, COL_INFO))
330 col_set_str(pinfo->cinfo, COL_INFO, "VJ uncompressed TCP (not enough data available)");
332 cs->flags |= SLF_TOSS;
333 cs = NULL; /* disable state updates */
335 /* Get the TCP header length */
336 thl = tvb_get_guint8(tvb, ihl + TCP_FIELD_HDR_LEN);
337 thl = ((thl & 0xf0) >> 4) * 4;
339 /* Check TCP header length */
340 if(thl < TCP_HDR_LEN) {
341 if(check_col(pinfo->cinfo, COL_INFO)) {
342 col_add_fstr(pinfo->cinfo, COL_INFO, "VJ uncompressed TCP (TCP header length (%u) < %u)",
346 cs->flags |= SLF_TOSS;
347 cs = NULL; /* disable state updates */
349 /* Make sure we have the full TCP header */
351 if(check_col(pinfo->cinfo, COL_INFO))
352 col_set_str(pinfo->cinfo, COL_INFO, "VJ uncompressed TCP (not enough data available)");
354 cs->flags |= SLF_TOSS;
355 cs = NULL; /* disable state updates */
362 * If packet seen for first time, update state if we have state and can
365 if(!pinfo->fd->flags.visited) {
367 cs->flags &= ~SLF_TOSS;
368 memcpy(&cs->cs_ip, &buffer[0], IP_HDR_LEN);
369 memcpy(&cs->cs_tcp, &buffer[ihl], TCP_HDR_LEN);
371 memcpy(cs->cs_ipopt, &buffer[sizeof(iphdr_type)], ihl - IP_HDR_LEN);
372 if(TCP_OFFSET(&(cs->cs_tcp)) > 5)
373 memcpy(cs->cs_tcpopt, &buffer[ihl + sizeof(tcphdr_type)],
374 (TCP_OFFSET(&(cs->cs_tcp)) - 5) * 4);
379 * Set up tvbuff containing packet with protocol type.
380 * Neither header checksum is recalculated.
382 * Use the length field from the IP header as the reported length;
383 * use the minimum of that and the number of bytes we got from
384 * the tvbuff as the actual length, just in case the tvbuff we were
385 * handed includes part or all of the FCS (because the FCS preference
386 * for the PPP dissector doesn't match the FCS size in this session).
388 ipsize = pntohs(&buffer[IP_FIELD_TOT_LEN]);
391 next_tvb = tvb_new_real_data(buffer, isize, ipsize);
392 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
393 add_new_data_source(pinfo, next_tvb, "VJ Uncompressed");
398 call_dissector(ip_handle, next_tvb, pinfo, tree);
401 /* Dissector for VJ Compressed packets */
403 dissect_vjc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
406 proto_tree *vj_tree = NULL;
407 tvbuff_t *next_tvb = NULL;
408 slcompress *comp = NULL;
411 if(check_col(pinfo->cinfo, COL_PROTOCOL))
412 col_set_str(pinfo->cinfo, COL_INFO, "PPP VJ");
415 ti = proto_tree_add_protocol_format(tree, proto_vj, tvb, 0, -1,
416 "PPP VJ Compression: Compressed data");
417 vj_tree = proto_item_add_subtree(ti, ett_vj);
420 if(!ppp_vj_decomp || pinfo->p2p_dir == P2P_DIR_UNKNOWN) {
422 * VJ decompression turned off, so we shouldn't decompress, or
423 * direction of the traffic unknown, so we can't decompress.
427 /* Get state for that direction */
428 comp = rx_tx_state[pinfo->p2p_dir];
431 /* Process the compressed data header */
432 if(vjc_process(tvb, pinfo, vj_tree, comp) == VJ_ERROR)
435 /* Decompression possible - set up tvb containing decompressed packet */
436 err = vjc_tvb_setup(tvb, &next_tvb, pinfo);
437 if(err == VJ_ERROR) {
439 call_dissector(data_handle, tvb, pinfo, vj_tree);
443 /* No errors, so call IP dissector */
444 call_dissector(ip_handle, next_tvb, pinfo, tree);
447 /* Registration functions for dissectors */
449 proto_register_vj(void)
451 static hf_register_info hf[] = {
452 { &hf_vj_change_mask,
453 { "Change mask", "vj.change_mask", FT_UINT8, BASE_HEX,
454 NULL, 0x0, "", HFILL }},
455 { &hf_vj_change_mask_c,
456 { "Connection changed", "vj.change_mask_c", FT_BOOLEAN, 8,
457 NULL, NEW_C, "Connection number changed", HFILL }},
458 { &hf_vj_change_mask_i,
459 { "IP ID change != 1", "vj.change_mask_i", FT_BOOLEAN, 8,
460 NULL, NEW_I, "IP ID changed by a value other than 1", HFILL }},
461 { &hf_vj_change_mask_p,
462 { "Push bit set", "vj.change_mask_p", FT_BOOLEAN, 8,
463 NULL, CHANGE_PUSH_BIT, "TCP PSH flag set", HFILL }},
464 { &hf_vj_change_mask_s,
465 { "Sequence number changed", "vj.change_mask_s", FT_BOOLEAN, 8,
466 NULL, NEW_S, "Sequence number changed", HFILL }},
467 { &hf_vj_change_mask_a,
468 { "Ack number changed", "vj.change_mask_a", FT_BOOLEAN, 8,
469 NULL, NEW_A, "Acknowledgement sequence number changed", HFILL }},
470 { &hf_vj_change_mask_w,
471 { "Window changed", "vj.change_mask_w", FT_BOOLEAN, 8,
472 NULL, NEW_W, "TCP window changed", HFILL }},
473 { &hf_vj_change_mask_u,
474 { "Urgent pointer set", "vj.change_mask_u", FT_BOOLEAN, 8,
475 NULL, NEW_U, "Urgent pointer set", HFILL }},
476 { &hf_vj_connection_number,
477 { "Connection number", "vj.connection_number", FT_UINT8, BASE_DEC,
478 NULL, 0x0, "Connection number", HFILL }},
480 { "TCP checksum", "vj.tcp_cksum", FT_UINT16, BASE_HEX,
481 NULL, 0x0, "TCP checksum", HFILL }},
483 { "Urgent pointer", "vj.urp", FT_UINT16, BASE_DEC,
484 NULL, 0x0, "Urgent pointer", HFILL }},
486 { "Window delta", "vj.win_delta", FT_INT16, BASE_DEC,
487 NULL, 0x0, "Delta for window", HFILL }},
489 { "Ack delta", "vj.ack_delta", FT_UINT16, BASE_DEC,
490 NULL, 0x0, "Delta for acknowledgment sequence number", HFILL }},
492 { "Sequence delta", "vj.seq_delta", FT_UINT16, BASE_DEC,
493 NULL, 0x0, "Delta for sequence number", HFILL }},
494 { &hf_vj_ip_id_delta,
495 { "IP ID delta", "vj.ip_id_delta", FT_UINT16, BASE_DEC,
496 NULL, 0x0, "Delta for IP ID", HFILL }},
498 static gint *ett[] = {
503 proto_vj = proto_register_protocol("PPP VJ Compression", "PPP VJ", "vj");
504 proto_register_field_array(proto_vj, hf, array_length(hf));
505 proto_register_subtree_array(ett, array_length(ett));
506 register_init_routine(&vj_init);
510 proto_reg_handoff_vj(void)
512 dissector_handle_t vjc_handle;
513 dissector_handle_t vjuc_handle;
515 vjc_handle = create_dissector_handle(dissect_vjc, proto_vj);
516 dissector_add("ppp.protocol", PPP_VJC_COMP, vjc_handle);
518 vjuc_handle = create_dissector_handle(dissect_vjuc, proto_vj);
519 dissector_add("ppp.protocol", PPP_VJC_UNCOMP, vjuc_handle);
521 ip_handle = find_dissector("ip");
522 data_handle = find_dissector("data");
525 /* Initialization function */
530 slcompress *pslc = NULL;
532 if(vj_header_memchunk != NULL)
533 g_mem_chunk_destroy(vj_header_memchunk);
534 vj_header_memchunk = g_mem_chunk_new("vj header store", sizeof (vj_header_t),
535 sizeof (vj_header_t) * VJ_ATOM_COUNT,
537 for(i = 0; i < RX_TX_STATE_COUNT; i++) {
538 if((pslc = rx_tx_state[i]) != NULL)
540 rx_tx_state[i] = slhc_init();
545 /* Initialization routine for VJ decompression */
549 slcompress *comp = g_malloc(sizeof(slcompress));
552 memset(comp, ZERO, sizeof(slcompress));
555 * Initialize the state; there is no current connection, and
556 * we have no header data for any of the connections, as we
557 * haven't yet seen an uncompressed frame.
559 comp->recv_current = TCP_SIMUL_CONV_MAX - 1;
560 for (i = 0; i < TCP_SIMUL_CONV_MAX; i++)
561 comp->rstate[i].flags |= SLF_TOSS;
565 /* Setup the decompressed packet tvb for VJ compressed packets */
567 vjc_tvb_setup(tvbuff_t *src_tvb,
571 vj_header_t *hdr_buf;
582 /* Get decompressed header stored in fd protocol area */
583 hdr_buf = p_get_proto_data(pinfo->fd, proto_vj);
584 if(hdr_buf == NULL) {
585 if(check_col(pinfo->cinfo, COL_INFO))
586 col_set_str(pinfo->cinfo, COL_INFO, "VJ compressed TCP (previous data bad or missing)");
590 if(check_col(pinfo->cinfo, COL_INFO))
591 col_set_str(pinfo->cinfo, COL_INFO, "VJ compressed TCP");
593 /* Get the data offset in the tvbuff */
594 offset = hdr_buf->offset;
596 /* Copy header and form tvb */
597 data_ptr = hdr_buf->data;
598 ip = (iphdr_type *)data_ptr;
599 hdr_len = lo_nibble(ip->ihl_version) * 4;
600 thp = (tcphdr_type *)(data_ptr + hdr_len);
601 hdr_len += TCP_OFFSET(thp) * 4;
602 buf_len = tvb_length(src_tvb) + hdr_len - offset;
603 pbuf = g_malloc(buf_len);
604 memcpy(pbuf, data_ptr, hdr_len);
605 tvb_memcpy(src_tvb, pbuf + hdr_len, offset, buf_len - hdr_len);
606 *dst_tvb = tvb_new_real_data(pbuf, buf_len, g_ntohs(ip->tot_len));
607 tvb_set_child_real_data_tvbuff(src_tvb, *dst_tvb);
608 add_new_data_source(pinfo, *dst_tvb, "VJ Decompressed");
613 * For VJ compressed packet:
615 * check if it is malformed;
616 * dissect the relevant fields;
617 * update the decompressor state on the first pass.
620 vjc_process(tvbuff_t *src_tvb, packet_info *pinfo, proto_tree *tree,
627 proto_tree *changes_tree;
630 iphdr_type *ip = NULL;
631 tcphdr_type *thp = NULL;
637 vj_header_t *buf_hdr;
640 if(tvb_length(src_tvb) < 3){
642 * We don't even have enough data for the change byte, so we can't
643 * determine which connection this is; mark all connections as
644 * non-decompressible.
646 if(check_col(pinfo->cinfo, COL_INFO))
647 col_set_str(pinfo->cinfo, COL_INFO, "VJ compressed TCP (not enough data available)");
649 call_dissector(data_handle, src_tvb, pinfo, tree);
651 for(i = 0; i < TCP_SIMUL_CONV_MAX; i++)
652 comp->rstate[i].flags |= SLF_TOSS;
657 /* Read the change byte */
658 changes = tvb_get_guint8(src_tvb, offset);
660 switch (changes & SPECIALS_MASK) {
663 ti = proto_tree_add_uint_format(tree, hf_vj_change_mask, src_tvb,
665 "Change mask: 0x%02x (echoed interactive traffic)",
670 ti = proto_tree_add_uint_format(tree, hf_vj_change_mask, src_tvb,
672 "Change mask: 0x%02x (unidirectional data)",
678 * XXX - summarize bits?
680 ti = proto_tree_add_uint_format(tree, hf_vj_change_mask, src_tvb,
682 "Change mask: 0x%02x", changes);
685 changes_tree = proto_item_add_subtree(ti, ett_vj_changes);
686 proto_tree_add_boolean(changes_tree, hf_vj_change_mask_c, src_tvb,
688 proto_tree_add_boolean(changes_tree, hf_vj_change_mask_i, src_tvb,
690 proto_tree_add_boolean(changes_tree, hf_vj_change_mask_p, src_tvb,
692 proto_tree_add_boolean(changes_tree, hf_vj_change_mask_s, src_tvb,
694 proto_tree_add_boolean(changes_tree, hf_vj_change_mask_a, src_tvb,
696 proto_tree_add_boolean(changes_tree, hf_vj_change_mask_w, src_tvb,
698 proto_tree_add_boolean(changes_tree, hf_vj_change_mask_u, src_tvb,
703 if(changes & NEW_C){ /* Read conn index */
704 conn_index = tvb_get_guint8(src_tvb, offset);
706 proto_tree_add_uint(tree, hf_vj_connection_number, src_tvb, offset, 1,
710 comp->recv_current = conn_index;
713 if(!pinfo->fd->flags.visited) {
715 * This is the first time this frame has been seen, so we need
716 * state information to decompress it. If that information isn't
717 * available, don't use the state information, and don't update it,
720 if(comp != NULL && !(comp->rstate[comp->recv_current].flags & SLF_TOSS)) {
721 cs = &comp->rstate[comp->recv_current];
727 /* Build TCP and IP headers */
728 tcp_cksum = tvb_get_ntohs(src_tvb, offset);
730 proto_tree_add_uint(tree, hf_vj_tcp_cksum, src_tvb, offset, 2, tcp_cksum);
732 hdrlen = lo_nibble(ip->ihl_version) * 4 + TCP_OFFSET(thp) * 4;
733 thp->cksum = g_htons(tcp_cksum);
737 if(changes & CHANGE_PUSH_BIT)
738 thp->flags |= TCP_PUSH_BIT;
740 thp->flags &= ~TCP_PUSH_BIT;
743 /* Deal with special cases and normal deltas */
744 switch(changes & SPECIALS_MASK){
745 case SPECIAL_I: /* Echoed terminal traffic */
747 word = g_ntohs(ip->tot_len) - hdrlen;
748 thp->ack_seq = g_htonl(g_ntohl(thp->ack_seq) + word);
749 thp->seq = g_htonl(g_ntohl(thp->seq) + word);
752 case SPECIAL_D: /* Unidirectional data */
754 thp->seq = g_htonl(g_ntohl(thp->seq) + g_ntohs(ip->tot_len) - hdrlen);
758 delta = get_unsigned_delta(src_tvb, &offset, hf_vj_urp, tree);
760 thp->urg_ptr = delta;
761 thp->flags |= TCP_URG_BIT;
765 thp->flags &= ~TCP_URG_BIT;
767 if(changes & NEW_W) {
768 delta = get_signed_delta(src_tvb, &offset, hf_vj_win_delta, tree);
770 thp->window = g_htons(g_ntohs(thp->window) + delta);
772 if(changes & NEW_A) {
773 delta = get_unsigned_delta(src_tvb, &offset, hf_vj_ack_delta, tree);
775 thp->ack_seq = g_htonl(g_ntohl(thp->ack_seq) + delta);
777 if(changes & NEW_S) {
778 delta = get_unsigned_delta(src_tvb, &offset, hf_vj_seq_delta, tree);
780 thp->seq = g_htonl(g_ntohl(thp->seq) + delta);
785 delta = get_unsigned_delta(src_tvb, &offset, hf_vj_ip_id_delta, tree);
789 ip->id = g_htons(g_ntohs(ip->id) + delta);
791 /* Compute IP packet length and the buffer length needed */
792 len = tvb_reported_length_remaining(src_tvb, offset);
795 * This shouldn't happen, as we *were* able to fetch stuff right before
798 if(check_col(pinfo->cinfo, COL_INFO))
799 col_set_str(pinfo->cinfo, COL_INFO, "VJ compressed TCP (not enough data available)");
801 cs->flags |= SLF_TOSS;
805 /* Show the TCP payload */
806 if(tree != NULL && tvb_offset_exists(src_tvb, offset))
807 proto_tree_add_text(tree, src_tvb, offset, -1, "TCP payload");
809 /* Nothing more to do if we don't have any compression state */
811 /* Direction of the traffic unknown - can't decompress */
812 if(check_col(pinfo->cinfo, COL_INFO))
813 col_set_str(pinfo->cinfo, COL_INFO, "VJ compressed TCP (direction unknown)");
819 ip->tot_len = g_htons(len);
820 /* Compute IP check sum */
822 ip->cksum = ip_csum((guint8 *)ip, lo_nibble(ip->ihl_version) * 4);
824 /* Store the reconstructed header in frame data area */
825 buf_hdr = g_mem_chunk_alloc(vj_header_memchunk);
826 buf_hdr->offset = offset; /* Offset in tvbuff is also stored */
827 data_ptr = buf_hdr->data;
828 memcpy(data_ptr, ip, IP_HDR_LEN);
829 data_ptr += IP_HDR_LEN;
830 if(lo_nibble(ip->ihl_version) > 5) {
831 memcpy(data_ptr, cs->cs_ipopt, (lo_nibble(ip->ihl_version) - 5) * 4);
832 data_ptr += (lo_nibble(ip->ihl_version) - 5) * 4;
834 memcpy(data_ptr, thp, TCP_HDR_LEN);
835 data_ptr += TCP_HDR_LEN;
836 if(TCP_OFFSET(thp) > 5)
837 memcpy(data_ptr, cs->cs_tcpopt, (TCP_OFFSET(thp) - 5) * 4);
838 p_add_proto_data(pinfo->fd, proto_vj, buf_hdr);
845 * Get an unsigned delta for a field, and put it into the protocol tree if
846 * we're building a protocol tree.
849 get_unsigned_delta(tvbuff_t *tvb, int *offsetp, int hf, proto_tree *tree)
851 int offset = *offsetp;
856 del = tvb_get_guint8(tvb, offset++);
858 del = tvb_get_ntohs(tvb, offset);
863 proto_tree_add_uint(tree, hf, tvb, *offsetp, len, del);
869 * Get a signed delta for a field, and put it into the protocol tree if
870 * we're building a protocol tree.
873 get_signed_delta(tvbuff_t *tvb, int *offsetp, int hf, proto_tree *tree)
875 int offset = *offsetp;
880 del = tvb_get_guint8(tvb, offset++);
882 del = tvb_get_ntohs(tvb, offset);
887 proto_tree_add_int(tree, hf, tvb, *offsetp, len, del);
892 /* Wrapper for in_cksum function */
894 ip_csum(const guint8 * ptr, guint32 len)
898 cksum_vec[0].ptr = ptr;
899 cksum_vec[0].len = len;
900 return in_cksum(&cksum_vec[0], 1);