2 * Routines for Van Jacobson header decompression.
4 * $Id: packet-vj.c,v 1.7 2002/04/14 23:22:22 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.
66 #ifdef HAVE_SYS_TYPES_H
67 # include <sys/types.h>
72 #include <epan/packet.h>
73 #include "packet-ppp.h"
76 #include "epan/tvbuff.h"
78 /* Define relevant IP/TCP parameters */
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_ADDR_SIZE 4 /* Size in bytes of IPv4 address */
82 #define IP_FIELD_PROTOCOL 9 /* Protocol field byte in IP hdr */
83 #define IP_PROTOCOL_TCP 0x06 /* Protocol field value for TCP */
84 #define IP_HDR_LEN 20 /* Minimum IP header length */
85 #define IP_HDR_LEN_MASK 0x0f /* Mask for header length field */
86 #define IP_MAX_OPT_LEN 44 /* Max length of IP options */
87 #define TCP_HDR_LEN 20 /* Minimum TCP header length */
88 #define TCP_MAX_OPT_LEN 44 /* Max length of TCP options */
89 #define TCP_SIMUL_CONV 256 /* Number of simul. TCP conversations */
90 #define TCP_SIMUL_CONV_MAX 256 /* Max number of simul. TCP conversations */
91 #define CHANGE_PUSH_BIT 0x10 /* TCP push bit changed */
92 #define TCP_PUSH_BIT 0x08 /* TCP push bit */
93 #define TCP_URG_BIT 0x20 /* TCP urgent bit */
95 /* Bits in first octet of compressed packet */
96 /* flag bits for what changed in a packet */
104 /* reserved, special-case values of above */
105 #define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */
106 #define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U)/* unidirectional data */
107 #define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U)
109 /* Function return values */
117 #define CRC_LEN sizeof(guint16)
119 /* VJ Mem Chunk defines */
120 #define VJ_DATA_SIZE 128 /* Max IP hdr(64)+Max TCP hdr(64) */
121 #define VJ_ATOM_COUNT 250 /* Number of Atoms per block */
123 /* IP and TCP header types */
149 #define TCP_OFFSET(th) (((th)->off_x2 & 0xf0) >> 4)
151 /* State per active tcp conversation */
152 typedef struct cstate {
153 struct cstate *next; /* next in ring (xmit) */
156 guint8 cs_ipopt[IP_MAX_OPT_LEN];
157 guint8 cs_tcpopt[TCP_MAX_OPT_LEN];
160 /* All the state data for one serial line */
162 cstate *rstate; /* receive connection states (array)*/
163 guint8 rslot_limit; /* highest receive slot id */
164 guint8 recv_current; /* most recent rcvd id */
166 #define SLF_TOSS 0x01 /* tossing rcvd frames until id received */
169 /* Initialize the protocol and registered fields */
170 static int proto_vj = -1;
172 /* Protocol handles */
173 static dissector_handle_t ip_handle;
174 static dissector_handle_t data_handle;
176 /* State repository (Full Duplex) */
177 #define RX_TX_STATE_COUNT 2
178 static slcompress *rx_tx_state[RX_TX_STATE_COUNT] = {NULL, NULL};
180 /* Mem Chunks for storing decompressed headers */
181 static GMemChunk *vj_header_memchunk = NULL;
184 guint8 data[VJ_DATA_SIZE];
187 /* Function prototypes */
188 static void decodes(tvbuff_t *tvb, guint32 *offset, gint16 *val);
189 static void decodel(tvbuff_t *tvb, guint32 *offset, gint32 *val);
190 static guint16 ip_csum(const guint8 *ptr, guint32 len);
191 static slcompress *slhc_init(gint rslots);
192 static void vj_init(void);
193 static gint vjuc_check(tvbuff_t *tvb, slcompress *comp);
194 static void vjuc_update_state(tvbuff_t *tvb, slcompress *comp, guint8 index);
195 static gint vjuc_tvb_setup(tvbuff_t *tvb, tvbuff_t **dst_tvb,
196 slcompress *comp, frame_data *fd);
197 static gint vjc_check(tvbuff_t *src_tvb, slcompress *comp);
198 static gint vjc_update_state(tvbuff_t *src_tvb, slcompress *comp,
200 static gint vjc_tvb_setup(tvbuff_t *src_tvb, tvbuff_t **dst_tvb,
203 /* Dissector for VJ Uncompressed packets */
205 dissect_vjuc(tvbuff_t *tvb, packet_info *pinfo, proto_tree * tree)
207 tvbuff_t *next_tvb = NULL;
208 slcompress *comp = NULL;
209 gint conn_index = ZERO;
212 /* Return if VJ is off or direction is not known */
213 if(ppp_vj_decomp == FALSE || pinfo->p2p_dir == P2P_DIR_UNKNOWN)
216 if((comp = rx_tx_state[pinfo->p2p_dir]) == NULL)
219 /* Check if packet malformed. */
221 err = conn_index = vjuc_check(tvb, comp);
223 /* Set up tvb containing decompressed packet */
225 err = vjuc_tvb_setup(tvb, &next_tvb, comp, pinfo->fd);
227 /* If packet seen for first time update state */
228 if(pinfo->fd->flags.visited != 1 && err == VJ_OK)
229 vjuc_update_state(next_tvb, comp, conn_index);
231 /* If no errors call IP dissector else dissect as data. */
233 call_dissector(ip_handle, next_tvb, pinfo, tree);
235 call_dissector(data_handle, tvb, pinfo, tree);
238 /* Dissector for VJ Compressed packets */
240 dissect_vjc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
242 tvbuff_t *next_tvb = NULL;
243 slcompress *comp = NULL;
246 /* Return if VJ is off or direction is not known */
247 if(ppp_vj_decomp == FALSE || pinfo->p2p_dir == P2P_DIR_UNKNOWN)
250 if((comp = rx_tx_state[pinfo->p2p_dir]) == NULL)
253 /* Check if packet malformed. */
255 err = vjc_check(tvb, comp);
257 /* If packet seen for first time update state */
258 if(pinfo->fd->flags.visited != 1 && err == VJ_OK) {
259 err = vjc_update_state(tvb, comp, pinfo->fd);
262 /* Set up tvb containing decompressed packet */
264 err = vjc_tvb_setup(tvb, &next_tvb, pinfo->fd);
266 /* If no errors call IP dissector else dissect as data */
268 call_dissector(ip_handle, next_tvb, pinfo, tree);
270 call_dissector(data_handle, tvb, pinfo, tree);
273 /* Registeration functions for dissectors */
275 proto_register_vj(void)
277 proto_vj = proto_register_protocol("PPP VJ Compression", "PPP VJ", "vj");
278 register_init_routine(&vj_init);
282 proto_reg_handoff_vj(void)
284 dissector_handle_t vjc_handle;
285 dissector_handle_t vjuc_handle;
287 vjc_handle = create_dissector_handle(dissect_vjc, proto_vj);
288 dissector_add("ppp.protocol", PPP_VJC_COMP, vjc_handle);
290 vjuc_handle = create_dissector_handle(dissect_vjuc, proto_vj);
291 dissector_add("ppp.protocol", PPP_VJC_UNCOMP, vjuc_handle);
293 ip_handle = find_dissector("ip");
294 data_handle = find_dissector("data");
297 /* Initialization function */
302 slcompress *pslc = NULL;
303 cstate *pstate = NULL;
305 if(vj_header_memchunk != NULL)
306 g_mem_chunk_destroy(vj_header_memchunk);
307 vj_header_memchunk = g_mem_chunk_new("vj header store", sizeof (vj_header_t),
308 sizeof (vj_header_t) * VJ_ATOM_COUNT,
310 for(i=0; i< RX_TX_STATE_COUNT; i++){
311 if((pslc = rx_tx_state[i]) != NULL){
312 if((pstate = pslc->rstate) != NULL)
316 rx_tx_state[i] = slhc_init(TCP_SIMUL_CONV);
321 /* Initialization routine for VJ decompression */
323 slhc_init(gint rslots)
325 size_t rsize = rslots * sizeof(cstate);
326 slcompress *comp = g_malloc(sizeof(slcompress));
328 if(rslots < ZERO || rslots > TCP_SIMUL_CONV_MAX)
332 memset(comp, ZERO, sizeof(slcompress));
333 if ((comp->rstate = g_malloc(rsize)) == NULL) {
338 memset(comp->rstate, ZERO, rsize);
339 comp->rslot_limit = rslots - 1;
340 comp->recv_current = TCP_SIMUL_CONV_MAX - 1;
341 comp->flags |= SLF_TOSS;
347 /* Setup the decompressed packet tvb for VJ compressed packets */
349 vjc_tvb_setup(tvbuff_t *src_tvb,
353 vj_header_t *hdr_buf;
358 guint8 offset = ZERO;
362 /* Get decompressed header stored in fd protocol area */
363 hdr_buf = p_get_proto_data(fd, proto_vj);
367 /* Get the data offset in the tvbuff */
368 offset = hdr_buf->offset;
370 /* Copy header and form tvb */
371 data_ptr = hdr_buf->data;
372 hdr_len = lo_nibble(((iphdr_type *)data_ptr)->ihl_version) * 4;
373 hdr_len += TCP_OFFSET(((tcphdr_type *)(data_ptr + hdr_len))) * 4;
374 buf_len = tvb_length(src_tvb) + hdr_len - offset;
375 pbuf = g_malloc(buf_len);
376 memcpy(pbuf, data_ptr, hdr_len);
377 tvb_memcpy(src_tvb, pbuf + hdr_len, offset, buf_len - hdr_len);
378 *dst_tvb = tvb_new_real_data(pbuf, buf_len, buf_len);
379 tvb_set_child_real_data_tvbuff(src_tvb, *dst_tvb);
380 add_new_data_source(fd, *dst_tvb, "VJ Decompressed");
384 /* For VJ compressed packets update the decompressor state */
386 vjc_update_state(tvbuff_t *src_tvb, slcompress *comp, frame_data *fd)
388 vj_header_t *buf_hdr;
390 cstate *cs = &comp->rstate[comp->recv_current];
391 tcphdr_type *thp = &cs->cs_tcp;
392 iphdr_type *ip = &cs->cs_ip;
396 guint32 offset = ZERO;
403 /* Read the change byte */
404 changes = tvb_get_guint8(src_tvb, offset++);
408 /* Build TCP and IP headers */
409 hdrlen = lo_nibble(ip->ihl_version) * 4 + TCP_OFFSET(thp) * 4;
410 thp->cksum = htons(tvb_get_ntohs(src_tvb, offset));
412 if (changes & CHANGE_PUSH_BIT)
413 thp->flags |= TCP_PUSH_BIT;
415 thp->flags &= ~TCP_PUSH_BIT;
417 /* Deal with special cases and normal deltas */
418 switch(changes & SPECIALS_MASK){
419 case SPECIAL_I: /* Echoed terminal traffic */
420 word = ntohs(ip->tot_len) - hdrlen;
421 thp->ack_seq = htonl( ntohl(thp->ack_seq) + word);
422 thp->seq = htonl( ntohl(thp->seq) + word);
424 case SPECIAL_D: /* Unidirectional data */
425 thp->seq = htonl( ntohl(thp->seq) + ntohs(ip->tot_len) - hdrlen);
430 decodes(src_tvb, &offset, &thp->urg_ptr);
431 thp->flags |= TCP_URG_BIT;
434 thp->flags &= ~TCP_URG_BIT;
436 decodes(src_tvb, &offset, &thp->window);
438 decodel(src_tvb, &offset, &thp->ack_seq);
440 decodel(src_tvb, &offset, &thp->seq);
444 decodes(src_tvb, &offset, &ip->id);
446 ip->id = htons (ntohs (ip->id) + 1);
448 /* Compute ip packet length and the buffer length needed */
449 if((len = tvb_length(src_tvb) - offset - CRC_LEN) < ZERO) {
450 comp->flags |= SLF_TOSS;
454 ip->tot_len = htons(len);
455 /* Compute IP check sum */
457 ip->cksum = ip_csum((guint8 *)ip, lo_nibble(ip->ihl_version) * 4);
459 /* Store the reconstructed header in frame data area */
460 buf_hdr = g_mem_chunk_alloc(vj_header_memchunk);
461 buf_hdr->offset = offset; /* Offset in tvbuff is also stored */
462 data_ptr = buf_hdr->data;
463 memcpy(data_ptr, ip, IP_HDR_LEN);
464 data_ptr += IP_HDR_LEN;
465 if(lo_nibble(ip->ihl_version) > 5) {
466 memcpy(data_ptr, cs->cs_ipopt, (lo_nibble(ip->ihl_version) - 5) * 4);
467 data_ptr += (lo_nibble(ip->ihl_version) - 5) * 4;
469 memcpy(data_ptr, thp, TCP_HDR_LEN);
470 data_ptr += TCP_HDR_LEN;
471 if(TCP_OFFSET(thp) > 5)
472 memcpy(data_ptr, cs->cs_tcpopt, (TCP_OFFSET(thp) - 5) * 4);
473 p_add_proto_data(fd, proto_vj, buf_hdr);
478 /* For VJ compressed packet check if it is malformed */
480 vjc_check(tvbuff_t *src_tvb, slcompress *comp)
482 guint8 conn_index = ZERO;
483 guint8 offset = ZERO;
489 if(tvb_length(src_tvb) < 3){
490 comp->flags |= SLF_TOSS;
494 /* Read the change byte */
495 changes = tvb_get_guint8(src_tvb, offset++);
497 if(changes & NEW_C){ /* Read conn index */
498 conn_index = tvb_get_guint8(src_tvb, offset++);
499 if(conn_index > comp->rslot_limit) {
500 comp->flags |= SLF_TOSS;
503 comp->flags &= ~SLF_TOSS;
504 comp->recv_current = conn_index;
507 if(comp->flags & SLF_TOSS)
514 /* Decode the delta of a 32 bit header field */
516 decodel(tvbuff_t *tvb, guint32* offset, gint32 *val)
518 gint del = tvb_get_guint8(tvb, (*offset)++);
520 del = tvb_get_ntohs(tvb, *offset);
521 *offset= *offset + 2;
523 *val = htonl(ntohl(*val) + del);
527 /* Decode the delta of a 16 bit header field */
529 decodes(tvbuff_t *tvb, guint32* offset, gint16 *val)
531 gint del = tvb_get_guint8(tvb, (*offset)++);
533 del = tvb_get_ntohs(tvb, *offset);
534 *offset= *offset + 2;
536 *val = htons(ntohs(*val) + del);
540 /* For VJ uncompressed packet check if it is malformed */
542 vjuc_check(tvbuff_t *tvb, slcompress *comp)
550 if(tvb_length(tvb) < IP_HDR_LEN) {
551 comp->flags |= SLF_TOSS;
555 /* Get the IP header length */
556 ihl = tvb_get_guint8(tvb, 0) & IP_HDR_LEN_MASK;
559 /* Get connection index */
560 index = tvb_get_guint8(tvb, IP_FIELD_PROTOCOL);
562 /* Check connection number and IP header length field */
563 if(ihl < IP_HDR_LEN || index > comp->rslot_limit) {
564 comp->flags |= SLF_TOSS;
572 /* Setup the decompressed packet tvb for VJ uncompressed packets */
574 vjuc_tvb_setup(tvbuff_t *tvb,
580 gint isize = tvb_length(tvb);
581 guint8 *buffer = NULL;
586 /* Get the IP header length */
587 ihl = tvb_get_guint8(tvb, 0) & IP_HDR_LEN_MASK;
590 /* Copy packet data to a buffer */
591 buffer = g_malloc(isize);
592 tvb_memcpy(tvb, buffer, 0, isize);
593 buffer[IP_FIELD_PROTOCOL] = IP_PROTOCOL_TCP;
595 /* Compute checksum */
596 if (ip_csum(buffer, ihl) != ZERO) {
598 comp->flags |= SLF_TOSS;
603 * Form the new tvbuff.
604 * Neither header checksum is recalculated
606 *dst_tvb = tvb_new_real_data(buffer, isize, isize);
607 tvb_set_child_real_data_tvbuff(tvb, *dst_tvb);
608 add_new_data_source(fd, *dst_tvb, "VJ Uncompressed");
612 /* For VJ uncompressed packets update the decompressor state */
614 vjuc_update_state(tvbuff_t *tvb, slcompress *comp, guint8 index)
622 /* Get the IP header length */
623 ihl = tvb_get_guint8(tvb, 0) & IP_HDR_LEN_MASK;
626 /* Update local state */
627 cs = &comp->rstate[comp->recv_current = index];
628 comp->flags &= ~SLF_TOSS;
629 tvb_memcpy(tvb, (guint8 *)&cs->cs_ip, 0, IP_HDR_LEN);
630 tvb_memcpy(tvb, (guint8 *)&cs->cs_tcp, ihl, TCP_HDR_LEN);
631 if (ihl > IP_HDR_LEN)
632 tvb_memcpy(tvb, cs->cs_ipopt, sizeof(iphdr_type), ihl - IP_HDR_LEN);
633 if (TCP_OFFSET(&(cs->cs_tcp)) > 5)
634 tvb_memcpy(tvb, cs->cs_tcpopt, ihl + sizeof(tcphdr_type),
635 (TCP_OFFSET(&(cs->cs_tcp)) - 5) * 4);
639 /* Wraper for in_cksum function */
641 ip_csum(const guint8 * ptr, guint32 len)
645 cksum_vec[0].ptr = ptr;
646 cksum_vec[0].len = len;
647 return in_cksum(&cksum_vec[0], 1);