From Chris Wilson:
[obnox/wireshark/wip.git] / packet-vj.c
1 /* packet-vj.c
2  * Routines for Van Jacobson header decompression.
3  *
4  * $Id: packet-vj.c,v 1.17 2003/08/26 05:52:53 guy Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@ethereal.com>
8  *
9  * This file created by Irfan Khan <ikhan@qualcomm.com>
10  * Copyright (c) 2001  by QUALCOMM, Incorporated.
11  * All Rights reserved.
12  *
13  * Routines to compress and uncompress TCP packets (for transmission
14  * over low speed serial lines).
15  *
16  * Copyright (c) 1989 Regents of the University of California.
17  * All rights reserved.
18  *
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.
30  *
31  *      Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
32  *      - Initial distribution.
33  *
34  *
35  * modified for KA9Q Internet Software Package by
36  * Katie Stevens (dkstevens@ucdavis.edu)
37  * University of California, Davis
38  * Computing Services
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
44  *
45  *      - Feb 1991      Bill_Simpson@um.cc.umich.edu
46  *                      variable number of conversation slots
47  *                      allow zero or one slots
48  *                      separate routines
49  *                      status display
50  *      - Jul 1994      Dmitry Gorodchanin
51  *                      Fixes for memory leaks.
52  *      - Oct 1994      Dmitry Gorodchanin
53  *                      Modularization.
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.
60  */
61
62 #ifdef HAVE_CONFIG_H
63 # include "config.h"
64 #endif
65
66 #include <glib.h>
67 #include <string.h>
68 #include <epan/packet.h>
69 #include "prefs.h"
70 #include "packet-ppp.h"
71 #include "ppptypes.h"
72 #include "ipproto.h"
73 #include "in_cksum.h"
74
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                         */
90
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                  */
100
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)
105
106 /* Function return values */
107 #define VJ_OK           0
108 #define VJ_ERROR       -1
109
110 /* Define for 0 */
111 #define ZERO            0
112
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      */
116
117 /* IP and TCP header types */
118 typedef struct {
119   guint8  ihl_version;
120   guint8  tos;
121   guint16 tot_len;
122   guint16 id;
123   guint16 frag_off;
124   guint8  ttl;
125   guint8  proto;
126   guint16 cksum;
127   guint32 src;
128   guint32 dst;
129 } iphdr_type;
130
131 typedef struct {
132   guint16 srcport;
133   guint16 dstport;
134   guint32 seq;
135   guint32 ack_seq;
136   guint8  off_x2;
137   guint8  flags;
138   guint16 window;
139   guint16 cksum;
140   guint16 urg_ptr;
141 } tcphdr_type;
142
143 #define TCP_OFFSET(th)  (((th)->off_x2 & 0xf0) >> 4)
144
145 /* State per active tcp conversation */
146 typedef struct cstate {
147   iphdr_type cs_ip;
148   tcphdr_type cs_tcp;
149   guint8 cs_ipopt[IP_MAX_OPT_LEN];
150   guint8 cs_tcpopt[TCP_MAX_OPT_LEN];
151   guint32 flags;
152 #define SLF_TOSS  0x00000001    /* tossing rcvd frames until id received */
153 } cstate;
154
155 /* All the state data for one serial line */
156 typedef struct {
157   cstate rstate[TCP_SIMUL_CONV_MAX]; /* receive connection states (array) */
158   guint8 recv_current;               /* most recent rcvd id */
159 } slcompress;
160
161 /* Initialize the protocol and registered fields */
162 static int proto_vj = -1;
163
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;
179
180 static gint ett_vj = -1;
181 static gint ett_vj_changes = -1;
182
183 /* Protocol handles */
184 static dissector_handle_t ip_handle;
185 static dissector_handle_t data_handle;
186
187 /* State repository (Full Duplex) */
188 #define RX_TX_STATE_COUNT 2
189 static slcompress *rx_tx_state[RX_TX_STATE_COUNT] = {NULL, NULL};
190
191 /* Mem Chunks for storing decompressed headers */
192 static GMemChunk *vj_header_memchunk = NULL;
193 typedef struct {
194         int     offset;                 /* uppermost bit is "can't dissect" flag */
195         guint8  data[VJ_DATA_SIZE];
196 } vj_header_t;
197
198 /* Function prototypes */
199 static int get_unsigned_delta(tvbuff_t *tvb, int *offsetp, int hf,
200                         proto_tree *tree);
201 static int get_signed_delta(tvbuff_t *tvb, int *offsetp, int hf,
202                         proto_tree *tree);
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,
207                       slcompress *comp);
208 static gint vjc_tvb_setup(tvbuff_t *src_tvb, tvbuff_t **dst_tvb,
209                           packet_info *pinfo);
210
211 /* Dissector for VJ Uncompressed packets */
212 static void
213 dissect_vjuc(tvbuff_t *tvb, packet_info *pinfo, proto_tree * tree)
214 {
215   proto_item *ti;
216   proto_tree *vj_tree     = NULL;
217   slcompress *comp;
218   int         i;
219   gint        conn_index;
220   cstate     *cs          = NULL;
221   guint8      ihl;
222   guint8      thl;
223   guint8     *buffer;
224   tvbuff_t   *next_tvb;
225   gint        isize       = tvb_length(tvb);
226   gint        ipsize;
227
228   if(check_col(pinfo->cinfo, COL_PROTOCOL))
229     col_set_str(pinfo->cinfo, COL_INFO, "PPP VJ");
230
231   if(tree != NULL) {
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);
235   }
236
237   if(pinfo->p2p_dir == P2P_DIR_UNKNOWN) {
238     /* Direction of the traffic unknown - can't update state */
239     comp = NULL;
240   } else {
241     /* Get state for that direction */
242     comp = rx_tx_state[pinfo->p2p_dir];
243   }
244
245   /*
246    * Check to make sure we can fetch the connection index.
247    */
248   if(!tvb_bytes_exist(tvb, IP_FIELD_PROTOCOL, 1)) {
249     /*
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.
253      */
254     if(check_col(pinfo->cinfo, COL_INFO))
255       col_set_str(pinfo->cinfo, COL_INFO, "VJ uncompressed TCP (not enough data available)");
256     if(tree != NULL)
257       call_dissector(data_handle, tvb, pinfo, tree);
258     if(comp != NULL) {
259       for(i = 0; i < TCP_SIMUL_CONV_MAX; i++)
260         comp->rstate[i].flags |= SLF_TOSS;
261     }
262     return;
263   }
264
265   /* Get connection index */
266   conn_index = tvb_get_guint8(tvb, IP_FIELD_PROTOCOL);
267   if(tree != NULL)
268     proto_tree_add_uint(vj_tree, hf_vj_connection_number, tvb,
269                         IP_FIELD_PROTOCOL, 1, conn_index);
270
271   /*
272    * Update the current connection, and get a pointer to its state.
273    */
274   if(comp != NULL) {
275     comp->recv_current = conn_index;
276     cs = &comp->rstate[conn_index];
277   }
278
279   /* Get the IP header length */
280   ihl = tvb_get_guint8(tvb, 0) & IP_HDR_LEN_MASK;
281   ihl <<= 2;
282
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)",
287                    ihl, IP_HDR_LEN);
288     }
289     if(cs != NULL)
290       cs->flags |= SLF_TOSS;
291     return;
292   }
293
294   /* Make sure we have the full IP header */
295   if(isize < ihl) {
296     if(check_col(pinfo->cinfo, COL_INFO))
297       col_set_str(pinfo->cinfo, COL_INFO, "VJ uncompressed TCP (not enough data available)");
298     if(tree != NULL)
299       call_dissector(data_handle, tvb, pinfo, tree);
300     if(cs != NULL)
301       cs->flags |= SLF_TOSS;
302     return;
303   }
304
305   if(check_col(pinfo->cinfo, COL_INFO))
306     col_set_str(pinfo->cinfo, COL_INFO, "VJ uncompressed TCP");
307
308   /*
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.
311    */
312   buffer = g_malloc(isize);
313   tvb_memcpy(tvb, buffer, 0, isize);
314   buffer[IP_FIELD_PROTOCOL] = IP_PROTO_TCP;
315
316   /* Check IP checksum */
317   if(ip_csum(buffer, ihl) != ZERO) {
318     /*
319      * Checksum invalid - don't update state, and don't decompress
320      * any subsequent compressed packets in this direction.
321      */
322     if(cs != NULL)
323       cs->flags |= SLF_TOSS;
324     cs = NULL;  /* disable state updates */
325   } else {
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)");
331       if(cs != NULL)
332         cs->flags |= SLF_TOSS;
333       cs = NULL;  /* disable state updates */
334     } else {
335       /* Get the TCP header length */
336       thl = tvb_get_guint8(tvb, ihl + TCP_FIELD_HDR_LEN);
337       thl = ((thl & 0xf0) >> 4) * 4;
338
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)",
343                        thl, TCP_HDR_LEN);
344         }
345         if(cs != NULL)
346           cs->flags |= SLF_TOSS;
347         cs = NULL;  /* disable state updates */
348       } else {
349         /* Make sure we have the full TCP header */
350         if(isize < thl) {
351           if(check_col(pinfo->cinfo, COL_INFO))
352             col_set_str(pinfo->cinfo, COL_INFO, "VJ uncompressed TCP (not enough data available)");
353           if(cs != NULL)
354             cs->flags |= SLF_TOSS;
355           cs = NULL;  /* disable state updates */
356         }
357       }
358     }
359   }
360
361   /*
362    * If packet seen for first time, update state if we have state and can
363    * update it.
364    */
365   if(!pinfo->fd->flags.visited) {
366     if(cs != NULL) {
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);
370       if(ihl > IP_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);
375     }
376   }
377
378   /*
379    * Set up tvbuff containing packet with protocol type.
380    * Neither header checksum is recalculated.
381    *
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).
387    */
388   ipsize = pntohs(&buffer[IP_FIELD_TOT_LEN]);
389   if (ipsize < isize)
390     isize = ipsize;
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");
394
395   /*
396    * Call IP dissector.
397    */
398   call_dissector(ip_handle, next_tvb, pinfo, tree);
399 }
400
401 /* Dissector for VJ Compressed packets */
402 static void
403 dissect_vjc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
404 {
405   proto_item *ti;
406   proto_tree *vj_tree     = NULL;
407   tvbuff_t   *next_tvb = NULL;
408   slcompress *comp     = NULL;
409   gint        err      = VJ_ERROR;
410
411   if(check_col(pinfo->cinfo, COL_PROTOCOL))
412     col_set_str(pinfo->cinfo, COL_INFO, "PPP VJ");
413
414   if(tree != NULL) {
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);
418   }
419
420   if(!ppp_vj_decomp || pinfo->p2p_dir == P2P_DIR_UNKNOWN) {
421     /*
422      * VJ decompression turned off, so we shouldn't decompress, or
423      * direction of the traffic unknown, so we can't decompress.
424      */
425     comp = NULL;
426   } else {
427     /* Get state for that direction */
428     comp = rx_tx_state[pinfo->p2p_dir];
429   }
430
431   /* Process the compressed data header */
432   if(vjc_process(tvb, pinfo, vj_tree, comp) == VJ_ERROR)
433     return;
434
435   /* Decompression possible - set up tvb containing decompressed packet */
436   err = vjc_tvb_setup(tvb, &next_tvb, pinfo);
437   if(err == VJ_ERROR) {
438     if(tree != NULL)
439       call_dissector(data_handle, tvb, pinfo, vj_tree);
440     return;
441   }
442
443   /* No errors, so call IP dissector */
444   call_dissector(ip_handle, next_tvb, pinfo, tree);
445 }
446
447 /* Registration functions for dissectors */
448 void
449 proto_register_vj(void)
450 {
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 }},
479     { &hf_vj_tcp_cksum,
480       { "TCP checksum",                 "vj.tcp_cksum", FT_UINT16, BASE_HEX,
481         NULL, 0x0, "TCP checksum", HFILL }},
482     { &hf_vj_urp,
483       { "Urgent pointer",               "vj.urp",       FT_UINT16, BASE_DEC,
484         NULL, 0x0, "Urgent pointer", HFILL }},
485     { &hf_vj_win_delta,
486       { "Window delta",                 "vj.win_delta", FT_INT16, BASE_DEC,
487         NULL, 0x0, "Delta for window", HFILL }},
488     { &hf_vj_ack_delta,
489       { "Ack delta",                    "vj.ack_delta", FT_UINT16, BASE_DEC,
490         NULL, 0x0, "Delta for acknowledgment sequence number", HFILL }},
491     { &hf_vj_seq_delta,
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 }},
497   };
498   static gint *ett[] = {
499     &ett_vj,
500     &ett_vj_changes,
501   };
502
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);
507 }
508
509 void
510 proto_reg_handoff_vj(void)
511 {
512   dissector_handle_t vjc_handle;
513   dissector_handle_t vjuc_handle;
514
515   vjc_handle = create_dissector_handle(dissect_vjc, proto_vj);
516   dissector_add("ppp.protocol", PPP_VJC_COMP, vjc_handle);
517
518   vjuc_handle = create_dissector_handle(dissect_vjuc, proto_vj);
519   dissector_add("ppp.protocol", PPP_VJC_UNCOMP, vjuc_handle);
520
521   ip_handle = find_dissector("ip");
522   data_handle = find_dissector("data");
523 }
524
525 /* Initialization function */
526 static void
527 vj_init(void)
528 {
529   gint i           = ZERO;
530   slcompress *pslc = NULL;
531
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,
536                                        G_ALLOC_ONLY);
537   for(i = 0; i < RX_TX_STATE_COUNT; i++) {
538     if((pslc = rx_tx_state[i]) != NULL)
539       g_free(pslc);
540     rx_tx_state[i] = slhc_init();
541   }
542   return;
543 }
544
545 /* Initialization routine for VJ decompression */
546 static slcompress *
547 slhc_init(void)
548 {
549   slcompress *comp = g_malloc(sizeof(slcompress));
550   int         i;
551
552   memset(comp, ZERO, sizeof(slcompress));
553
554   /*
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.
558    */
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;
562   return comp;
563 }
564
565 /* Setup the decompressed packet tvb for VJ compressed packets */
566 static gint
567 vjc_tvb_setup(tvbuff_t *src_tvb,
568               tvbuff_t **dst_tvb,
569               packet_info *pinfo)
570 {
571   vj_header_t *hdr_buf;
572   guint8       offset;
573   guint8      *data_ptr;
574   iphdr_type  *ip;
575   tcphdr_type *thp;
576   gint         hdr_len;
577   gint         buf_len;
578   guint8      *pbuf;
579
580   g_assert(src_tvb);
581
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)");
587     return VJ_ERROR;
588   }
589
590   if(check_col(pinfo->cinfo, COL_INFO))
591     col_set_str(pinfo->cinfo, COL_INFO, "VJ compressed TCP");
592
593   /* Get the data offset in the tvbuff */
594   offset  = hdr_buf->offset;
595
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");
609   return VJ_OK;
610 }
611
612 /*
613  * For VJ compressed packet:
614  *
615  *      check if it is malformed;
616  *      dissect the relevant fields;
617  *      update the decompressor state on the first pass.
618  */
619 static gint
620 vjc_process(tvbuff_t *src_tvb, packet_info *pinfo, proto_tree *tree,
621             slcompress *comp)
622 {
623   int            offset     = ZERO;
624   int            i;
625   gint           changes;
626   proto_item    *ti;
627   proto_tree    *changes_tree;
628   guint8         conn_index;
629   cstate        *cs         = NULL;
630   iphdr_type    *ip         = NULL;
631   tcphdr_type   *thp        = NULL;
632   guint16        tcp_cksum;
633   gint           hdrlen     = ZERO;
634   guint16        word;
635   int            delta;
636   gint           len;
637   vj_header_t   *buf_hdr;
638   guint8        *data_ptr;
639
640   if(tvb_length(src_tvb) < 3){
641     /*
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.
645      */
646     if(check_col(pinfo->cinfo, COL_INFO))
647       col_set_str(pinfo->cinfo, COL_INFO, "VJ compressed TCP (not enough data available)");
648     if(tree != NULL)
649       call_dissector(data_handle, src_tvb, pinfo, tree);
650     if(comp != NULL) {
651       for(i = 0; i < TCP_SIMUL_CONV_MAX; i++)
652         comp->rstate[i].flags |= SLF_TOSS;
653     }
654     return VJ_ERROR;
655   }
656
657   /* Read the change byte */
658   changes = tvb_get_guint8(src_tvb, offset);
659   if(tree != NULL) {
660     switch (changes & SPECIALS_MASK) {
661
662     case SPECIAL_I:
663       ti = proto_tree_add_uint_format(tree, hf_vj_change_mask, src_tvb,
664                                       offset, 1, changes,
665                                       "Change mask: 0x%02x (echoed interactive traffic)",
666                                       changes);
667       break;
668
669     case SPECIAL_D:
670       ti = proto_tree_add_uint_format(tree, hf_vj_change_mask, src_tvb,
671                                       offset, 1, changes,
672                                       "Change mask: 0x%02x (unidirectional data)",
673                                       changes);
674       break;
675
676     default:
677       /*
678        * XXX - summarize bits?
679        */
680       ti = proto_tree_add_uint_format(tree, hf_vj_change_mask, src_tvb,
681                                       offset, 1, changes,
682                                       "Change mask: 0x%02x", changes);
683       break;
684     }
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,
687                            offset, 1, changes);
688     proto_tree_add_boolean(changes_tree, hf_vj_change_mask_i, src_tvb,
689                            offset, 1, changes);
690     proto_tree_add_boolean(changes_tree, hf_vj_change_mask_p, src_tvb,
691                            offset, 1, changes);
692     proto_tree_add_boolean(changes_tree, hf_vj_change_mask_s, src_tvb,
693                            offset, 1, changes);
694     proto_tree_add_boolean(changes_tree, hf_vj_change_mask_a, src_tvb,
695                            offset, 1, changes);
696     proto_tree_add_boolean(changes_tree, hf_vj_change_mask_w, src_tvb,
697                            offset, 1, changes);
698     proto_tree_add_boolean(changes_tree, hf_vj_change_mask_u, src_tvb,
699                            offset, 1, changes);
700   }
701   offset++;
702
703   if(changes & NEW_C){    /* Read conn index */
704     conn_index = tvb_get_guint8(src_tvb, offset);
705     if(tree != NULL)
706       proto_tree_add_uint(tree, hf_vj_connection_number, src_tvb, offset, 1,
707                           conn_index);
708     offset++;
709     if(comp != NULL)
710       comp->recv_current = conn_index;
711   }
712
713   if(!pinfo->fd->flags.visited) {
714     /*
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,
718      * either.
719      */
720     if(comp != NULL && !(comp->rstate[comp->recv_current].flags & SLF_TOSS)) {
721       cs = &comp->rstate[comp->recv_current];
722       thp = &cs->cs_tcp;
723       ip = &cs->cs_ip;
724     }
725   }
726
727   /* Build TCP and IP headers */
728   tcp_cksum = tvb_get_ntohs(src_tvb, offset);
729   if(tree != NULL)
730     proto_tree_add_uint(tree, hf_vj_tcp_cksum, src_tvb, offset, 2, tcp_cksum);
731   if(cs != NULL) {
732     hdrlen = lo_nibble(ip->ihl_version) * 4 + TCP_OFFSET(thp) * 4;
733     thp->cksum = g_htons(tcp_cksum);
734   }
735   offset += 2;
736   if(cs != NULL) {
737     if(changes & CHANGE_PUSH_BIT)
738       thp->flags |= TCP_PUSH_BIT;
739     else
740       thp->flags &= ~TCP_PUSH_BIT;
741   }
742
743   /* Deal with special cases and normal deltas */
744   switch(changes & SPECIALS_MASK){
745     case SPECIAL_I:                   /* Echoed terminal traffic */
746       if(cs != NULL) {
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);
750       }
751       break;
752     case SPECIAL_D:                   /* Unidirectional data */
753       if(cs != NULL)
754         thp->seq = g_htonl(g_ntohl(thp->seq) + g_ntohs(ip->tot_len) - hdrlen);
755       break;
756     default:
757       if(changes & NEW_U){
758         delta = get_unsigned_delta(src_tvb, &offset, hf_vj_urp, tree);
759         if(cs != NULL) {
760           thp->urg_ptr = delta;
761           thp->flags |= TCP_URG_BIT;
762         }
763       } else {
764         if(cs != NULL)
765           thp->flags &= ~TCP_URG_BIT;
766       }
767       if(changes & NEW_W) {
768         delta = get_signed_delta(src_tvb, &offset, hf_vj_win_delta, tree);
769         if(cs != NULL)
770           thp->window = g_htons(g_ntohs(thp->window) + delta);
771       }
772       if(changes & NEW_A) {
773         delta = get_unsigned_delta(src_tvb, &offset, hf_vj_ack_delta, tree);
774         if(cs != NULL)
775           thp->ack_seq = g_htonl(g_ntohl(thp->ack_seq) + delta);
776       }
777       if(changes & NEW_S) {
778         delta = get_unsigned_delta(src_tvb, &offset, hf_vj_seq_delta, tree);
779         if(cs != NULL)
780           thp->seq = g_htonl(g_ntohl(thp->seq) + delta);
781       }
782       break;
783   }
784   if(changes & NEW_I)
785     delta = get_unsigned_delta(src_tvb, &offset, hf_vj_ip_id_delta, tree);
786   else
787     delta = 1;
788   if(cs != NULL)
789     ip->id = g_htons(g_ntohs(ip->id) + delta);
790
791   /* Compute IP packet length and the buffer length needed */
792   len = tvb_reported_length_remaining(src_tvb, offset);
793   if(len < ZERO) {
794     /*
795      * This shouldn't happen, as we *were* able to fetch stuff right before
796      * offset.
797      */
798     if(check_col(pinfo->cinfo, COL_INFO))
799       col_set_str(pinfo->cinfo, COL_INFO, "VJ compressed TCP (not enough data available)");
800     if(cs != NULL)
801       cs->flags |= SLF_TOSS;
802     return VJ_ERROR;
803   }
804
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");
808
809   /* Nothing more to do if we don't have any compression state */
810   if(comp == NULL) {
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)");
814     return VJ_ERROR;
815   }
816
817   if(cs != NULL) {
818     len += hdrlen;
819     ip->tot_len = g_htons(len);
820     /* Compute IP check sum */
821     ip->cksum = ZERO;
822     ip->cksum = ip_csum((guint8 *)ip, lo_nibble(ip->ihl_version) * 4);
823
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;
833     }
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);
839   }
840
841   return VJ_OK;
842 }
843
844 /*
845  * Get an unsigned delta for a field, and put it into the protocol tree if
846  * we're building a protocol tree.
847  */
848 static int
849 get_unsigned_delta(tvbuff_t *tvb, int *offsetp, int hf, proto_tree *tree)
850 {
851   int offset = *offsetp;
852   int len;
853   guint16 del;
854
855   len = 1;
856   del = tvb_get_guint8(tvb, offset++);
857   if(del == ZERO){
858     del = tvb_get_ntohs(tvb, offset);
859     offset += 2;
860     len += 2;
861   }
862   if(tree != NULL)
863     proto_tree_add_uint(tree, hf, tvb, *offsetp, len, del);
864   *offsetp = offset;
865   return del;
866 }
867
868 /*
869  * Get a signed delta for a field, and put it into the protocol tree if
870  * we're building a protocol tree.
871  */
872 static int
873 get_signed_delta(tvbuff_t *tvb, int *offsetp, int hf, proto_tree *tree)
874 {
875   int offset = *offsetp;
876   int len;
877   gint16 del;
878
879   len = 1;
880   del = tvb_get_guint8(tvb, offset++);
881   if(del == ZERO){
882     del = tvb_get_ntohs(tvb, offset);
883     offset += 2;
884     len += 2;
885   }
886   if(tree != NULL)
887     proto_tree_add_int(tree, hf, tvb, *offsetp, len, del);
888   *offsetp = offset;
889   return del;
890 }
891
892 /* Wrapper for in_cksum function */
893 static guint16
894 ip_csum(const guint8 * ptr, guint32 len)
895 {
896   vec_t cksum_vec[1];
897
898   cksum_vec[0].ptr = ptr;
899   cksum_vec[0].len = len;
900   return in_cksum(&cksum_vec[0], 1);
901 }