aboutsummaryrefslogtreecommitdiffstats
path: root/src/gprs/slhc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gprs/slhc.c')
-rw-r--r--src/gprs/slhc.c813
1 files changed, 0 insertions, 813 deletions
diff --git a/src/gprs/slhc.c b/src/gprs/slhc.c
deleted file mode 100644
index cbdf8dbd8..000000000
--- a/src/gprs/slhc.c
+++ /dev/null
@@ -1,813 +0,0 @@
-/*
- * 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
- *
- *
- * This module is a difficult issue. It's clearly inet code but it's also clearly
- * driver code belonging close to PPP and SLIP
- */
-
-#include <string.h>
-#include <stdio.h>
-#include <errno.h>
-#include <stdint.h>
-#include <arpa/inet.h>
-#include <osmocom/core/utils.h>
-#include <osmocom/core/talloc.h>
-#include <openbsc/slhc.h>
-#include <openbsc/debug.h>
-
-#define ERR_PTR(x) x
-
-
-static unsigned char *encode(unsigned char *cp, unsigned short n);
-static long decode(unsigned char **cpp);
-static unsigned char * put16(unsigned char *cp, unsigned short x);
-static unsigned short pull16(unsigned char **cpp);
-
-/* Replacement for kernel space function ip_fast_csum() */
-static uint16_t ip_fast_csum(uint8_t *iph, int ihl)
-{
- int i;
- uint16_t temp;
- uint32_t accumulator = 0xFFFF;
-
- for(i=0;i<ihl*2;i++)
- {
- temp = ((*iph) << 8)&0xFF00;
- iph++;
- temp |= (*iph)&0xFF;
- iph++;
-
- accumulator+=temp;
- if(accumulator>0xFFFF)
- {
- accumulator++;
- accumulator&=0xFFFF;
- }
- }
-
- return (uint16_t)(htons(~accumulator)&0xFFFF);
-}
-
-/* Replacement for kernel space function put_unaligned() */
-static void put_unaligned(uint16_t val, void *ptr)
-{
- memcpy(ptr,&val,sizeof(val));
-}
-
-
-/* Allocate compression data structure
- * slots must be in range 0 to 255 (zero meaning no compression)
- * Returns pointer to structure or ERR_PTR() on error.
- */
-struct slcompress *
-slhc_init(const void *ctx, int rslots, int tslots)
-{
- register short i;
- register struct cstate *ts;
- struct slcompress *comp;
-
- if (rslots < 0 || rslots > 255 || tslots < 0 || tslots > 255)
- return NULL;
-
- comp = (struct slcompress *)talloc_zero_size(ctx,sizeof(struct slcompress));
- if (! comp)
- goto out_fail;
-
- if (rslots > 0) {
- size_t rsize = rslots * sizeof(struct cstate);
- comp->rstate = (struct cstate *) talloc_zero_size(ctx, rsize);
- if (! comp->rstate)
- goto out_free;
- comp->rslot_limit = rslots - 1;
- }
-
- if (tslots > 0) {
- size_t tsize = tslots * sizeof(struct cstate);
- comp->tstate = (struct cstate *) talloc_zero_size(ctx, tsize);
- if (! comp->tstate)
- goto out_free2;
- comp->tslot_limit = tslots - 1;
- }
-
- comp->xmit_oldest = 0;
- comp->xmit_current = 255;
- comp->recv_current = 255;
- /*
- * don't accept any packets with implicit index until we get
- * one with an explicit index. Otherwise the uncompress code
- * will try to use connection 255, which is almost certainly
- * out of range
- */
- comp->flags |= SLF_TOSS;
-
- if ( tslots > 0 ) {
- ts = comp->tstate;
- for(i = comp->tslot_limit; i > 0; --i){
- ts[i].cs_this = i;
- ts[i].next = &(ts[i - 1]);
- }
- ts[0].next = &(ts[comp->tslot_limit]);
- ts[0].cs_this = 0;
- }
- return comp;
-
-out_free2:
- talloc_free(comp->rstate);
-out_free:
- talloc_free(comp);
-out_fail:
- return NULL;
-}
-
-
-/* Free a compression data structure */
-void
-slhc_free(struct slcompress *comp)
-{
- DEBUGP(DSLHC, "slhc_free(): Freeing compression states...\n");
-
- if ( comp == NULLSLCOMPR )
- return;
-
- if ( comp->tstate != NULLSLSTATE )
- talloc_free(comp->tstate );
-
- if ( comp->rstate != NULLSLSTATE )
- talloc_free( comp->rstate );
-
- talloc_free( comp );
-}
-
-
-/* Put a short in host order into a char array in network order */
-static inline unsigned char *
-put16(unsigned char *cp, unsigned short x)
-{
- *cp++ = x >> 8;
- *cp++ = x;
-
- return cp;
-}
-
-
-/* Encode a number */
-static unsigned char *
-encode(unsigned char *cp, unsigned short n)
-{
- if(n >= 256 || n == 0){
- *cp++ = 0;
- cp = put16(cp,n);
- } else {
- *cp++ = n;
- }
-
- DEBUGP(DSLHC, "encode(): n=%04x\n",n);
- return cp;
-}
-
-/* Pull a 16-bit integer in host order from buffer in network byte order */
-static unsigned short
-pull16(unsigned char **cpp)
-{
- short rval;
-
- rval = *(*cpp)++;
- rval <<= 8;
- rval |= *(*cpp)++;
- return rval;
-}
-
-/* Decode a number */
-static long
-decode(unsigned char **cpp)
-{
- register int x;
-
- x = *(*cpp)++;
- if(x == 0){
- return pull16(cpp) & 0xffff; /* pull16 returns -1 on error */
- } else {
- return x & 0xff; /* -1 if PULLCHAR returned error */
- }
-}
-
-/*
- * icp and isize are the original packet.
- * ocp is a place to put a copy if necessary.
- * cpp is initially a pointer to icp. If the copy is used,
- * change it to ocp.
- */
-
-int
-slhc_compress(struct slcompress *comp, unsigned char *icp, int isize,
- unsigned char *ocp, unsigned char **cpp, int compress_cid)
-{
- register struct cstate *ocs = &(comp->tstate[comp->xmit_oldest]);
- register struct cstate *lcs = ocs;
- register struct cstate *cs = lcs->next;
- register unsigned long deltaS, deltaA;
- register short changes = 0;
- int hlen;
- unsigned char new_seq[16];
- register unsigned char *cp = new_seq;
- struct iphdr *ip;
- struct tcphdr *th, *oth;
- __sum16 csum;
-
-
- /*
- * Don't play with runt packets.
- */
-
- if(isize<sizeof(struct iphdr))
- return isize;
-
- ip = (struct iphdr *) icp;
-
- /* Bail if this packet isn't TCP, or is an IP fragment */
- if (ip->protocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x3fff)) {
- /* Send as regular IP */
- if(ip->protocol != IPPROTO_TCP)
- comp->sls_o_nontcp++;
- else
- comp->sls_o_tcp++;
- DEBUGP(DSLHC, "slhc_compress(): Not a TCP packat, will not touch...\n");
- return isize;
- }
- /* Extract TCP header */
-
- th = (struct tcphdr *)(((unsigned char *)ip) + ip->ihl*4);
- hlen = ip->ihl*4 + th->doff*4;
-
- /* Bail if the TCP packet isn't `compressible' (i.e., ACK isn't set or
- * some other control bit is set). Also uncompressible if
- * it's a runt.
- */
- if(hlen > isize || th->syn || th->fin || th->rst ||
- ! (th->ack)){
- /* TCP connection stuff; send as regular IP */
- comp->sls_o_tcp++;
- DEBUGP(DSLHC, "slhc_compress(): Packet is part of a TCP connection, will not touch...\n");
- return isize;
- }
- /*
- * Packet is compressible -- we're going to send either a
- * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way,
- * we need to locate (or create) the connection state.
- *
- * States are kept in a circularly linked list with
- * xmit_oldest pointing to the end of the list. The
- * list is kept in lru order by moving a state to the
- * head of the list whenever it is referenced. Since
- * the list is short and, empirically, the connection
- * we want is almost always near the front, we locate
- * states via linear search. If we don't find a state
- * for the datagram, the oldest state is (re-)used.
- */
-
- DEBUGP(DSLHC, "slhc_compress(): Compressible packet detected!\n");
-
- for ( ; ; ) {
- if( ip->saddr == cs->cs_ip.saddr
- && ip->daddr == cs->cs_ip.daddr
- && th->source == cs->cs_tcp.source
- && th->dest == cs->cs_tcp.dest)
- goto found;
-
- /* if current equal oldest, at end of list */
- if ( cs == ocs )
- break;
- lcs = cs;
- cs = cs->next;
- comp->sls_o_searches++;
- }
- /*
- * Didn't find it -- re-use oldest cstate. Send an
- * uncompressed packet that tells the other side what
- * connection number we're using for this conversation.
- *
- * Note that since the state list is circular, the oldest
- * state points to the newest and we only need to set
- * xmit_oldest to update the lru linkage.
- */
-
- DEBUGP(DSLHC, "slhc_compress(): Header not yet seen, will memorize header for the next turn...\n");
- comp->sls_o_misses++;
- comp->xmit_oldest = lcs->cs_this;
- goto uncompressed;
-
-found:
- DEBUGP(DSLHC, "slhc_compress(): Header already seen, trying to compress...\n");
- /*
- * Found it -- move to the front on the connection list.
- */
- if(lcs == ocs) {
- /* found at most recently used */
- } else if (cs == ocs) {
- /* found at least recently used */
- comp->xmit_oldest = lcs->cs_this;
- } else {
- /* more than 2 elements */
- lcs->next = cs->next;
- cs->next = ocs->next;
- ocs->next = cs;
- }
-
- /*
- * Make sure that only what we expect to change changed.
- * Check the following:
- * IP protocol version, header length & type of service.
- * The "Don't fragment" bit.
- * The time-to-live field.
- * The TCP header length.
- * IP options, if any.
- * TCP options, if any.
- * If any of these things are different between the previous &
- * current datagram, we send the current datagram `uncompressed'.
- */
- oth = &cs->cs_tcp;
-
- /* Display a little more debug information about which of the
- * header fields changed unexpectedly */
- if(ip->version != cs->cs_ip.version)
- DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->version != cs->cs_ip.version\n");
- if(ip->ihl != cs->cs_ip.ihl)
- DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->ihl != cs->cs_ip.ihl\n");
- if(ip->tos != cs->cs_ip.tos)
- DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->tos != cs->cs_ip.tos\n");
- if((ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000)))
- DEBUGP(DSLHC, "slhc_compress(): Unexpected change: (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000))\n");
- if(ip->ttl != cs->cs_ip.ttl)
- DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->ttl != cs->cs_ip.ttl\n");
- if(th->doff != cs->cs_tcp.doff)
- DEBUGP(DSLHC, "slhc_compress(): Unexpected change: th->doff != cs->cs_tcp.doff\n");
- if(ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) {
- DEBUGP(DSLHC, "slhc_compress(): Unexpected change: (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0)\n");
- DEBUGP(DSLHC, "slhc_compress(): ip->ihl = %i\n", ip->ihl);
- DEBUGP(DSLHC, "slhc_compress(): ip+1 = %s\n",
- osmo_hexdump_nospc((uint8_t*)(ip+1),((ip->ihl)-5)*4));
- DEBUGP(DSLHC, "slhc_compress(): Unexpected change: cs->cs_ipopt = %s\n",
- osmo_hexdump_nospc((uint8_t*)(cs->cs_ipopt),((ip->ihl)-5)*4));
- }
- if(th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0) {
- DEBUGP(DSLHC, "slhc_compress(): Unexpected change: (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)\n");
- DEBUGP(DSLHC, "slhc_compress(): th->doff = %i\n", th->doff);
- DEBUGP(DSLHC, "slhc_compress(): th+1 = %s\n",
- osmo_hexdump_nospc((uint8_t*)(th+1),((th->doff)-5)*4));
- DEBUGP(DSLHC, "slhc_compress(): cs->cs_tcpopt = %s\n",
- osmo_hexdump_nospc((uint8_t*)cs->cs_tcpopt,
- ((th->doff)-5)*4));
- }
-
-
- if(ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl
- || ip->tos != cs->cs_ip.tos
- || (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000))
- || ip->ttl != cs->cs_ip.ttl
- || th->doff != cs->cs_tcp.doff
- || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0)
- || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)){
- DEBUGP(DSLHC, "slhc_compress(): The header contains unexpected changes, can't compress...\n");
- goto uncompressed;
- }
-
- /*
- * Figure out which of the changing fields changed. The
- * receiver expects changes in the order: urgent, window,
- * ack, seq (the order minimizes the number of temporaries
- * needed in this section of code).
- */
- if(th->urg){
- deltaS = ntohs(th->urg_ptr);
- DEBUGP(DSLHC, "slhc_compress(): flag: Urgent Pointer (U) = 1\n");
- cp = encode(cp,deltaS);
- changes |= NEW_U;
- } else if(th->urg_ptr != oth->urg_ptr){
- /* argh! URG not set but urp changed -- a sensible
- * implementation should never do this but RFC793
- * doesn't prohibit the change so we have to deal
- * with it. */
- DEBUGP(DSLHC, "slhc_compress(): URG not set but urp changed, can't compress...\n");
- goto uncompressed;
- }
- if((deltaS = ntohs(th->window) - ntohs(oth->window)) != 0){
- DEBUGP(DSLHC, "slhc_compress(): flag: Delta Window (W) = 1\n");
- cp = encode(cp,deltaS);
- changes |= NEW_W;
- }
- if((deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L){
- if(deltaA > 0x0000ffff) {
- DEBUGP(DSLHC, "slhc_compress(): (deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L, can't compress...\n");
- goto uncompressed;
- }
- DEBUGP(DSLHC, "slhc_compress(): flag: Delta Ack (A) = 1\n");
- cp = encode(cp,deltaA);
- changes |= NEW_A;
- }
- if((deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L){
- if(deltaS > 0x0000ffff) {
- DEBUGP(DSLHC, "slhc_compress(): (deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L, can't compress...\n");
- goto uncompressed;
- }
- DEBUGP(DSLHC, "slhc_compress(): flag: Delta Sequence (S) = 1\n");
- cp = encode(cp,deltaS);
- changes |= NEW_S;
- }
-
- switch(changes){
- case 0: /* Nothing changed. If this packet contains data and the
- * last one didn't, this is probably a data packet following
- * an ack (normal on an interactive connection) and we send
- * it compressed. Otherwise it's probably a retransmit,
- * retransmitted ack or window probe. Send it uncompressed
- * in case the other side missed the compressed version.
- */
- if(ip->tot_len != cs->cs_ip.tot_len &&
- ntohs(cs->cs_ip.tot_len) == hlen)
- break;
- DEBUGP(DSLHC, "slhc_compress(): Retransmitted packet detected, can't compress...\n");
- goto uncompressed;
- case SPECIAL_I:
- case SPECIAL_D:
- /* actual changes match one of our special case encodings --
- * send packet uncompressed.
- */
- DEBUGP(DSLHC, "slhc_compress(): Special case detected, can't compress...\n");
- goto uncompressed;
- case NEW_S|NEW_A:
- if(deltaS == deltaA &&
- deltaS == ntohs(cs->cs_ip.tot_len) - hlen){
- /* special case for echoed terminal traffic */
- DEBUGP(DSLHC, "slhc_compress(): Special case for echoed terminal traffic detected...\n");
- DEBUGP(DSLHC, "slhc_compress(): flag: Delta Sequence (S) = 1, Delta Window (W) = 1, Urgent Pointer (U) = 1\n");
- changes = SPECIAL_I;
- cp = new_seq;
- }
- break;
- case NEW_S:
- if(deltaS == ntohs(cs->cs_ip.tot_len) - hlen){
- /* special case for data xfer */
- DEBUGP(DSLHC, "slhc_compress(): Special case for data xfer detected...\n");
- DEBUGP(DSLHC, "slhc_compress(): flag: Delta Sequence (S) = 1, Delta Ack (A) = 1, Delta Window (W) = 1, Urgent Pointer (U) = 1\n");
- changes = SPECIAL_D;
- cp = new_seq;
- }
- break;
- }
- deltaS = ntohs(ip->id) - ntohs(cs->cs_ip.id);
- if(deltaS != 1){
- DEBUGP(DSLHC, "slhc_compress(): flag: Delta IP ID (I) = 1\n");
- cp = encode(cp,deltaS);
- changes |= NEW_I;
- }
- if(th->psh) {
- DEBUGP(DSLHC, "slhc_compress(): flag: Push (P) = 1\n");
- changes |= TCP_PUSH_BIT;
- }
- /* Grab the cksum before we overwrite it below. Then update our
- * state with this packet's header.
- */
- csum = th->check;
- memcpy(&cs->cs_ip,ip,20);
- memcpy(&cs->cs_tcp,th,20);
- /* We want to use the original packet as our compressed packet.
- * (cp - new_seq) is the number of bytes we need for compressed
- * sequence numbers. In addition we need one byte for the change
- * mask, one for the connection id and two for the tcp checksum.
- * So, (cp - new_seq) + 4 bytes of header are needed.
- */
- deltaS = cp - new_seq;
- if(compress_cid == 0 || comp->xmit_current != cs->cs_this){
- cp = ocp;
- *cpp = ocp;
- DEBUGP(DSLHC, "slhc_compress(): flag: Connection number (C) = 1\n");
- *cp++ = changes | NEW_C;
- *cp++ = cs->cs_this;
- comp->xmit_current = cs->cs_this;
- } else {
- cp = ocp;
- *cpp = ocp;
- *cp++ = changes;
- }
- *(__sum16 *)cp = csum;
- cp += 2;
-/* deltaS is now the size of the change section of the compressed header */
-
- DEBUGP(DSLHC, "slhc_compress(): Delta-list length (deltaS) = %li\n",deltaS);
- DEBUGP(DSLHC, "slhc_compress(): Original header len (hlen) = %i\n",hlen);
-
- memcpy(cp,new_seq,deltaS); /* Write list of deltas */
- memcpy(cp+deltaS,icp+hlen,isize-hlen);
- comp->sls_o_compressed++;
- ocp[0] |= SL_TYPE_COMPRESSED_TCP;
- return isize - hlen + deltaS + (cp - ocp);
-
- /* Update connection state cs & send uncompressed packet (i.e.,
- * a regular ip/tcp packet but with the 'conversation id' we hope
- * to use on future compressed packets in the protocol field).
- */
-uncompressed:
- DEBUGP(DSLHC, "slhc_compress(): Packet will be sent uncompressed...\n");
- memcpy(&cs->cs_ip,ip,20);
- memcpy(&cs->cs_tcp,th,20);
- if (ip->ihl > 5)
- memcpy(cs->cs_ipopt, ip+1, ((ip->ihl) - 5) * 4);
- if (th->doff > 5)
- memcpy(cs->cs_tcpopt, th+1, ((th->doff) - 5) * 4);
- comp->xmit_current = cs->cs_this;
- comp->sls_o_uncompressed++;
- memcpy(ocp, icp, isize);
- *cpp = ocp;
- ocp[9] = cs->cs_this;
- ocp[0] |= SL_TYPE_UNCOMPRESSED_TCP;
- return isize;
-}
-
-
-int
-slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)
-{
- register int changes;
- long x;
- register struct tcphdr *thp;
- register struct iphdr *ip;
- register struct cstate *cs;
- int len, hdrlen;
- unsigned char *cp = icp;
-
- /* We've got a compressed packet; read the change byte */
- comp->sls_i_compressed++;
- if(isize < 3){
- comp->sls_i_error++;
- return 0;
- }
- changes = *cp++;
- if(changes & NEW_C){
- /* Make sure the state index is in range, then grab the state.
- * If we have a good state index, clear the 'discard' flag.
- */
- x = *cp++; /* Read conn index */
- if(x < 0 || x > comp->rslot_limit)
- goto bad;
-
- comp->flags &=~ SLF_TOSS;
- comp->recv_current = x;
- } else {
- /* this packet has an implicit state index. If we've
- * had a line error since the last time we got an
- * explicit state index, we have to toss the packet. */
- if(comp->flags & SLF_TOSS){
- comp->sls_i_tossed++;
- return 0;
- }
- }
- cs = &comp->rstate[comp->recv_current];
- thp = &cs->cs_tcp;
- ip = &cs->cs_ip;
-
- thp->check = *(__sum16 *)cp;
- cp += 2;
-
- thp->psh = (changes & TCP_PUSH_BIT) ? 1 : 0;
-/*
- * we can use the same number for the length of the saved header and
- * the current one, because the packet wouldn't have been sent
- * as compressed unless the options were the same as the previous one
- */
-
- hdrlen = ip->ihl * 4 + thp->doff * 4;
-
- switch(changes & SPECIALS_MASK){
- case SPECIAL_I: /* Echoed terminal traffic */
- DEBUGP(DSLHC, "slhc_uncompress(): Echoed terminal traffic detected\n");
-
- {
- register short i;
- i = ntohs(ip->tot_len) - hdrlen;
- thp->ack_seq = htonl( ntohl(thp->ack_seq) + i);
- thp->seq = htonl( ntohl(thp->seq) + i);
- }
- break;
-
- case SPECIAL_D: /* Unidirectional data */
- DEBUGP(DSLHC, "slhc_uncompress(): Unidirectional data detected\n");
- thp->seq = htonl( ntohl(thp->seq) +
- ntohs(ip->tot_len) - hdrlen);
- break;
-
- default:
- DEBUGP(DSLHC, "slhc_uncompress(): default packet type detected\n");
- if(changes & NEW_U){
- thp->urg = 1;
- if((x = decode(&cp)) == -1) {
- goto bad;
- }
- thp->urg_ptr = htons(x);
- } else
- thp->urg = 0;
- if(changes & NEW_W){
- if((x = decode(&cp)) == -1) {
- goto bad;
- }
- thp->window = htons( ntohs(thp->window) + x);
- }
- if(changes & NEW_A){
- if((x = decode(&cp)) == -1) {
- goto bad;
- }
- thp->ack_seq = htonl( ntohl(thp->ack_seq) + x);
- }
- if(changes & NEW_S){
- if((x = decode(&cp)) == -1) {
- goto bad;
- }
- thp->seq = htonl( ntohl(thp->seq) + x);
- }
- break;
- }
- if(changes & NEW_I){
- if((x = decode(&cp)) == -1) {
- goto bad;
- }
- ip->id = htons (ntohs (ip->id) + x);
- } else
- ip->id = htons (ntohs (ip->id) + 1);
-
- /*
- * At this point, cp points to the first byte of data in the
- * packet. Put the reconstructed TCP and IP headers back on the
- * packet. Recalculate IP checksum (but not TCP checksum).
- */
-
- len = isize - (cp - icp);
- if (len < 0)
- goto bad;
- len += hdrlen;
- ip->tot_len = htons(len);
- ip->check = 0;
-
- DEBUGP(DSLHC, "slhc_uncompress(): making space for the reconstructed header...\n");
- memmove(icp + hdrlen, cp, len - hdrlen);
-
- cp = icp;
- memcpy(cp, ip, 20);
- cp += 20;
-
- if (ip->ihl > 5) {
- memcpy(cp, cs->cs_ipopt, (ip->ihl - 5) * 4);
- cp += (ip->ihl - 5) * 4;
- }
-
- put_unaligned(ip_fast_csum(icp, ip->ihl),
- &((struct iphdr *)icp)->check);
-
- memcpy(cp, thp, 20);
- cp += 20;
-
- if (thp->doff > 5) {
- memcpy(cp, cs->cs_tcpopt, ((thp->doff) - 5) * 4);
- cp += ((thp->doff) - 5) * 4;
- }
-
- return len;
-bad:
- DEBUGP(DSLHC, "slhc_uncompress(): bad packet detected!\n");
- comp->sls_i_error++;
- return slhc_toss( comp );
-}
-
-
-int
-slhc_remember(struct slcompress *comp, unsigned char *icp, int isize)
-{
- register struct cstate *cs;
- unsigned ihl;
-
- unsigned char index;
-
- if(isize < 20) {
- /* The packet is shorter than a legal IP header */
- comp->sls_i_runt++;
- DEBUGP(DSLHC, "slhc_remember(): The packet is shorter than a legal IP header ==> slhc_toss()\n");
- return slhc_toss( comp );
- }
- /* Peek at the IP header's IHL field to find its length */
- ihl = icp[0] & 0xf;
- if(ihl < 20 / 4){
- /* The IP header length field is too small */
- comp->sls_i_runt++;
- DEBUGP(DSLHC, "slhc_remember(): The IP header length field is too small ==> slhc_toss()\n");
- return slhc_toss( comp );
- }
- index = icp[9];
- icp[9] = IPPROTO_TCP;
-
- if (ip_fast_csum(icp, ihl)) {
- /* Bad IP header checksum; discard */
- comp->sls_i_badcheck++;
- DEBUGP(DSLHC, "slhc_remember(): Bad IP header checksum; discard ==> slhc_toss()\n");
- return slhc_toss( comp );
- }
- if(index > comp->rslot_limit) {
- comp->sls_i_error++;
- DEBUGP(DSLHC, "slhc_remember(): index > comp->rslot_limit ==> slhc_toss()\n");
- return slhc_toss(comp);
- }
-
- /* Update local state */
- cs = &comp->rstate[comp->recv_current = index];
- comp->flags &=~ SLF_TOSS;
- memcpy(&cs->cs_ip,icp,20);
- memcpy(&cs->cs_tcp,icp + ihl*4,20);
- if (ihl > 5)
- memcpy(cs->cs_ipopt, icp + sizeof(struct iphdr), (ihl - 5) * 4);
- if (cs->cs_tcp.doff > 5)
- memcpy(cs->cs_tcpopt, icp + ihl*4 + sizeof(struct tcphdr), (cs->cs_tcp.doff - 5) * 4);
- cs->cs_hsize = ihl*2 + cs->cs_tcp.doff*2;
- /* Put headers back on packet
- * Neither header checksum is recalculated
- */
- comp->sls_i_uncompressed++;
- return isize;
-}
-
-int
-slhc_toss(struct slcompress *comp)
-{
- DEBUGP(DSLHC, "slhc_toss(): Reset compression state...\n");
- if ( comp == NULLSLCOMPR )
- return 0;
-
- comp->flags |= SLF_TOSS;
- return 0;
-}
-
-void slhc_i_status(struct slcompress *comp)
-{
- if (comp != NULLSLCOMPR) {
- DEBUGP(DSLHC, "slhc_i_status(): %d Cmp, %d Uncmp, %d Bad, %d Tossed\n",
- comp->sls_i_compressed,
- comp->sls_i_uncompressed,
- comp->sls_i_error,
- comp->sls_i_tossed);
- }
-}
-
-void slhc_o_status(struct slcompress *comp)
-{
- if (comp != NULLSLCOMPR) {
- DEBUGP(DSLHC, "slhc_o_status(): %d Cmp, %d Uncmp, %d AsIs, %d NotTCP %d Searches, %d Misses\n",
- comp->sls_o_compressed,
- comp->sls_o_uncompressed,
- comp->sls_o_tcp,
- comp->sls_o_nontcp,
- comp->sls_o_searches,
- comp->sls_o_misses);
- }
-}
-