linux/drivers/net/slip/slhc.c
<<
>>
Prefs
   1/*
   2 * Routines to compress and uncompress tcp packets (for transmission
   3 * over low speed serial lines).
   4 *
   5 * Copyright (c) 1989 Regents of the University of California.
   6 * All rights reserved.
   7 *
   8 * Redistribution and use in source and binary forms are permitted
   9 * provided that the above copyright notice and this paragraph are
  10 * duplicated in all such forms and that any documentation,
  11 * advertising materials, and other materials related to such
  12 * distribution and use acknowledge that the software was developed
  13 * by the University of California, Berkeley.  The name of the
  14 * University may not be used to endorse or promote products derived
  15 * from this software without specific prior written permission.
  16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  19 *
  20 *      Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
  21 *      - Initial distribution.
  22 *
  23 *
  24 * modified for KA9Q Internet Software Package by
  25 * Katie Stevens (dkstevens@ucdavis.edu)
  26 * University of California, Davis
  27 * Computing Services
  28 *      - 01-31-90      initial adaptation (from 1.19)
  29 *      PPP.05  02-15-90 [ks]
  30 *      PPP.08  05-02-90 [ks]   use PPP protocol field to signal compression
  31 *      PPP.15  09-90    [ks]   improve mbuf handling
  32 *      PPP.16  11-02    [karn] substantially rewritten to use NOS facilities
  33 *
  34 *      - Feb 1991      Bill_Simpson@um.cc.umich.edu
  35 *                      variable number of conversation slots
  36 *                      allow zero or one slots
  37 *                      separate routines
  38 *                      status display
  39 *      - Jul 1994      Dmitry Gorodchanin
  40 *                      Fixes for memory leaks.
  41 *      - Oct 1994      Dmitry Gorodchanin
  42 *                      Modularization.
  43 *      - Jan 1995      Bjorn Ekwall
  44 *                      Use ip_fast_csum from ip.h
  45 *      - July 1995     Christos A. Polyzols
  46 *                      Spotted bug in tcp option checking
  47 *
  48 *
  49 *      This module is a difficult issue. It's clearly inet code but it's also clearly
  50 *      driver code belonging close to PPP and SLIP
  51 */
  52
  53#include <linux/module.h>
  54#include <linux/slab.h>
  55#include <linux/types.h>
  56#include <linux/string.h>
  57#include <linux/errno.h>
  58#include <linux/kernel.h>
  59#include <net/slhc_vj.h>
  60
  61#ifdef CONFIG_INET
  62/* Entire module is for IP only */
  63#include <linux/mm.h>
  64#include <linux/socket.h>
  65#include <linux/sockios.h>
  66#include <linux/termios.h>
  67#include <linux/in.h>
  68#include <linux/fcntl.h>
  69#include <linux/inet.h>
  70#include <linux/netdevice.h>
  71#include <net/ip.h>
  72#include <net/protocol.h>
  73#include <net/icmp.h>
  74#include <net/tcp.h>
  75#include <linux/skbuff.h>
  76#include <net/sock.h>
  77#include <linux/timer.h>
  78#include <asm/uaccess.h>
  79#include <net/checksum.h>
  80#include <asm/unaligned.h>
  81
  82static unsigned char *encode(unsigned char *cp, unsigned short n);
  83static long decode(unsigned char **cpp);
  84static unsigned char * put16(unsigned char *cp, unsigned short x);
  85static unsigned short pull16(unsigned char **cpp);
  86
  87/* Initialize compression data structure
  88 *      slots must be in range 0 to 255 (zero meaning no compression)
  89 */
  90struct slcompress *
  91slhc_init(int rslots, int tslots)
  92{
  93        register short i;
  94        register struct cstate *ts;
  95        struct slcompress *comp;
  96
  97        comp = kzalloc(sizeof(struct slcompress), GFP_KERNEL);
  98        if (! comp)
  99                goto out_fail;
 100
 101        if ( rslots > 0  &&  rslots < 256 ) {
 102                size_t rsize = rslots * sizeof(struct cstate);
 103                comp->rstate = kzalloc(rsize, GFP_KERNEL);
 104                if (! comp->rstate)
 105                        goto out_free;
 106                comp->rslot_limit = rslots - 1;
 107        }
 108
 109        if ( tslots > 0  &&  tslots < 256 ) {
 110                size_t tsize = tslots * sizeof(struct cstate);
 111                comp->tstate = kzalloc(tsize, GFP_KERNEL);
 112                if (! comp->tstate)
 113                        goto out_free2;
 114                comp->tslot_limit = tslots - 1;
 115        }
 116
 117        comp->xmit_oldest = 0;
 118        comp->xmit_current = 255;
 119        comp->recv_current = 255;
 120        /*
 121         * don't accept any packets with implicit index until we get
 122         * one with an explicit index.  Otherwise the uncompress code
 123         * will try to use connection 255, which is almost certainly
 124         * out of range
 125         */
 126        comp->flags |= SLF_TOSS;
 127
 128        if ( tslots > 0 ) {
 129                ts = comp->tstate;
 130                for(i = comp->tslot_limit; i > 0; --i){
 131                        ts[i].cs_this = i;
 132                        ts[i].next = &(ts[i - 1]);
 133                }
 134                ts[0].next = &(ts[comp->tslot_limit]);
 135                ts[0].cs_this = 0;
 136        }
 137        return comp;
 138
 139out_free2:
 140        kfree(comp->rstate);
 141out_free:
 142        kfree(comp);
 143out_fail:
 144        return NULL;
 145}
 146
 147
 148/* Free a compression data structure */
 149void
 150slhc_free(struct slcompress *comp)
 151{
 152        if ( comp == NULLSLCOMPR )
 153                return;
 154
 155        if ( comp->tstate != NULLSLSTATE )
 156                kfree( comp->tstate );
 157
 158        if ( comp->rstate != NULLSLSTATE )
 159                kfree( comp->rstate );
 160
 161        kfree( comp );
 162}
 163
 164
 165/* Put a short in host order into a char array in network order */
 166static inline unsigned char *
 167put16(unsigned char *cp, unsigned short x)
 168{
 169        *cp++ = x >> 8;
 170        *cp++ = x;
 171
 172        return cp;
 173}
 174
 175
 176/* Encode a number */
 177static unsigned char *
 178encode(unsigned char *cp, unsigned short n)
 179{
 180        if(n >= 256 || n == 0){
 181                *cp++ = 0;
 182                cp = put16(cp,n);
 183        } else {
 184                *cp++ = n;
 185        }
 186        return cp;
 187}
 188
 189/* Pull a 16-bit integer in host order from buffer in network byte order */
 190static unsigned short
 191pull16(unsigned char **cpp)
 192{
 193        short rval;
 194
 195        rval = *(*cpp)++;
 196        rval <<= 8;
 197        rval |= *(*cpp)++;
 198        return rval;
 199}
 200
 201/* Decode a number */
 202static long
 203decode(unsigned char **cpp)
 204{
 205        register int x;
 206
 207        x = *(*cpp)++;
 208        if(x == 0){
 209                return pull16(cpp) & 0xffff;    /* pull16 returns -1 on error */
 210        } else {
 211                return x & 0xff;                /* -1 if PULLCHAR returned error */
 212        }
 213}
 214
 215/*
 216 * icp and isize are the original packet.
 217 * ocp is a place to put a copy if necessary.
 218 * cpp is initially a pointer to icp.  If the copy is used,
 219 *    change it to ocp.
 220 */
 221
 222int
 223slhc_compress(struct slcompress *comp, unsigned char *icp, int isize,
 224        unsigned char *ocp, unsigned char **cpp, int compress_cid)
 225{
 226        register struct cstate *ocs = &(comp->tstate[comp->xmit_oldest]);
 227        register struct cstate *lcs = ocs;
 228        register struct cstate *cs = lcs->next;
 229        register unsigned long deltaS, deltaA;
 230        register short changes = 0;
 231        int hlen;
 232        unsigned char new_seq[16];
 233        register unsigned char *cp = new_seq;
 234        struct iphdr *ip;
 235        struct tcphdr *th, *oth;
 236        __sum16 csum;
 237
 238
 239        /*
 240         *      Don't play with runt packets.
 241         */
 242
 243        if(isize<sizeof(struct iphdr))
 244                return isize;
 245
 246        ip = (struct iphdr *) icp;
 247
 248        /* Bail if this packet isn't TCP, or is an IP fragment */
 249        if (ip->protocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x3fff)) {
 250                /* Send as regular IP */
 251                if(ip->protocol != IPPROTO_TCP)
 252                        comp->sls_o_nontcp++;
 253                else
 254                        comp->sls_o_tcp++;
 255                return isize;
 256        }
 257        /* Extract TCP header */
 258
 259        th = (struct tcphdr *)(((unsigned char *)ip) + ip->ihl*4);
 260        hlen = ip->ihl*4 + th->doff*4;
 261
 262        /*  Bail if the TCP packet isn't `compressible' (i.e., ACK isn't set or
 263         *  some other control bit is set). Also uncompressible if
 264         *  it's a runt.
 265         */
 266        if(hlen > isize || th->syn || th->fin || th->rst ||
 267            ! (th->ack)){
 268                /* TCP connection stuff; send as regular IP */
 269                comp->sls_o_tcp++;
 270                return isize;
 271        }
 272        /*
 273         * Packet is compressible -- we're going to send either a
 274         * COMPRESSED_TCP or UNCOMPRESSED_TCP packet.  Either way,
 275         * we need to locate (or create) the connection state.
 276         *
 277         * States are kept in a circularly linked list with
 278         * xmit_oldest pointing to the end of the list.  The
 279         * list is kept in lru order by moving a state to the
 280         * head of the list whenever it is referenced.  Since
 281         * the list is short and, empirically, the connection
 282         * we want is almost always near the front, we locate
 283         * states via linear search.  If we don't find a state
 284         * for the datagram, the oldest state is (re-)used.
 285         */
 286        for ( ; ; ) {
 287                if( ip->saddr == cs->cs_ip.saddr
 288                 && ip->daddr == cs->cs_ip.daddr
 289                 && th->source == cs->cs_tcp.source
 290                 && th->dest == cs->cs_tcp.dest)
 291                        goto found;
 292
 293                /* if current equal oldest, at end of list */
 294                if ( cs == ocs )
 295                        break;
 296                lcs = cs;
 297                cs = cs->next;
 298                comp->sls_o_searches++;
 299        }
 300        /*
 301         * Didn't find it -- re-use oldest cstate.  Send an
 302         * uncompressed packet that tells the other side what
 303         * connection number we're using for this conversation.
 304         *
 305         * Note that since the state list is circular, the oldest
 306         * state points to the newest and we only need to set
 307         * xmit_oldest to update the lru linkage.
 308         */
 309        comp->sls_o_misses++;
 310        comp->xmit_oldest = lcs->cs_this;
 311        goto uncompressed;
 312
 313found:
 314        /*
 315         * Found it -- move to the front on the connection list.
 316         */
 317        if(lcs == ocs) {
 318                /* found at most recently used */
 319        } else if (cs == ocs) {
 320                /* found at least recently used */
 321                comp->xmit_oldest = lcs->cs_this;
 322        } else {
 323                /* more than 2 elements */
 324                lcs->next = cs->next;
 325                cs->next = ocs->next;
 326                ocs->next = cs;
 327        }
 328
 329        /*
 330         * Make sure that only what we expect to change changed.
 331         * Check the following:
 332         * IP protocol version, header length & type of service.
 333         * The "Don't fragment" bit.
 334         * The time-to-live field.
 335         * The TCP header length.
 336         * IP options, if any.
 337         * TCP options, if any.
 338         * If any of these things are different between the previous &
 339         * current datagram, we send the current datagram `uncompressed'.
 340         */
 341        oth = &cs->cs_tcp;
 342
 343        if(ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl
 344         || ip->tos != cs->cs_ip.tos
 345         || (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000))
 346         || ip->ttl != cs->cs_ip.ttl
 347         || th->doff != cs->cs_tcp.doff
 348         || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0)
 349         || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)){
 350                goto uncompressed;
 351        }
 352
 353        /*
 354         * Figure out which of the changing fields changed.  The
 355         * receiver expects changes in the order: urgent, window,
 356         * ack, seq (the order minimizes the number of temporaries
 357         * needed in this section of code).
 358         */
 359        if(th->urg){
 360                deltaS = ntohs(th->urg_ptr);
 361                cp = encode(cp,deltaS);
 362                changes |= NEW_U;
 363        } else if(th->urg_ptr != oth->urg_ptr){
 364                /* argh! URG not set but urp changed -- a sensible
 365                 * implementation should never do this but RFC793
 366                 * doesn't prohibit the change so we have to deal
 367                 * with it. */
 368                goto uncompressed;
 369        }
 370        if((deltaS = ntohs(th->window) - ntohs(oth->window)) != 0){
 371                cp = encode(cp,deltaS);
 372                changes |= NEW_W;
 373        }
 374        if((deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L){
 375                if(deltaA > 0x0000ffff)
 376                        goto uncompressed;
 377                cp = encode(cp,deltaA);
 378                changes |= NEW_A;
 379        }
 380        if((deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L){
 381                if(deltaS > 0x0000ffff)
 382                        goto uncompressed;
 383                cp = encode(cp,deltaS);
 384                changes |= NEW_S;
 385        }
 386
 387        switch(changes){
 388        case 0: /* Nothing changed. If this packet contains data and the
 389                 * last one didn't, this is probably a data packet following
 390                 * an ack (normal on an interactive connection) and we send
 391                 * it compressed.  Otherwise it's probably a retransmit,
 392                 * retransmitted ack or window probe.  Send it uncompressed
 393                 * in case the other side missed the compressed version.
 394                 */
 395                if(ip->tot_len != cs->cs_ip.tot_len &&
 396                   ntohs(cs->cs_ip.tot_len) == hlen)
 397                        break;
 398                goto uncompressed;
 399                break;
 400        case SPECIAL_I:
 401        case SPECIAL_D:
 402                /* actual changes match one of our special case encodings --
 403                 * send packet uncompressed.
 404                 */
 405                goto uncompressed;
 406        case NEW_S|NEW_A:
 407                if(deltaS == deltaA &&
 408                    deltaS == ntohs(cs->cs_ip.tot_len) - hlen){
 409                        /* special case for echoed terminal traffic */
 410                        changes = SPECIAL_I;
 411                        cp = new_seq;
 412                }
 413                break;
 414        case NEW_S:
 415                if(deltaS == ntohs(cs->cs_ip.tot_len) - hlen){
 416                        /* special case for data xfer */
 417                        changes = SPECIAL_D;
 418                        cp = new_seq;
 419                }
 420                break;
 421        }
 422        deltaS = ntohs(ip->id) - ntohs(cs->cs_ip.id);
 423        if(deltaS != 1){
 424                cp = encode(cp,deltaS);
 425                changes |= NEW_I;
 426        }
 427        if(th->psh)
 428                changes |= TCP_PUSH_BIT;
 429        /* Grab the cksum before we overwrite it below.  Then update our
 430         * state with this packet's header.
 431         */
 432        csum = th->check;
 433        memcpy(&cs->cs_ip,ip,20);
 434        memcpy(&cs->cs_tcp,th,20);
 435        /* We want to use the original packet as our compressed packet.
 436         * (cp - new_seq) is the number of bytes we need for compressed
 437         * sequence numbers.  In addition we need one byte for the change
 438         * mask, one for the connection id and two for the tcp checksum.
 439         * So, (cp - new_seq) + 4 bytes of header are needed.
 440         */
 441        deltaS = cp - new_seq;
 442        if(compress_cid == 0 || comp->xmit_current != cs->cs_this){
 443                cp = ocp;
 444                *cpp = ocp;
 445                *cp++ = changes | NEW_C;
 446                *cp++ = cs->cs_this;
 447                comp->xmit_current = cs->cs_this;
 448        } else {
 449                cp = ocp;
 450                *cpp = ocp;
 451                *cp++ = changes;
 452        }
 453        *(__sum16 *)cp = csum;
 454        cp += 2;
 455/* deltaS is now the size of the change section of the compressed header */
 456        memcpy(cp,new_seq,deltaS);      /* Write list of deltas */
 457        memcpy(cp+deltaS,icp+hlen,isize-hlen);
 458        comp->sls_o_compressed++;
 459        ocp[0] |= SL_TYPE_COMPRESSED_TCP;
 460        return isize - hlen + deltaS + (cp - ocp);
 461
 462        /* Update connection state cs & send uncompressed packet (i.e.,
 463         * a regular ip/tcp packet but with the 'conversation id' we hope
 464         * to use on future compressed packets in the protocol field).
 465         */
 466uncompressed:
 467        memcpy(&cs->cs_ip,ip,20);
 468        memcpy(&cs->cs_tcp,th,20);
 469        if (ip->ihl > 5)
 470          memcpy(cs->cs_ipopt, ip+1, ((ip->ihl) - 5) * 4);
 471        if (th->doff > 5)
 472          memcpy(cs->cs_tcpopt, th+1, ((th->doff) - 5) * 4);
 473        comp->xmit_current = cs->cs_this;
 474        comp->sls_o_uncompressed++;
 475        memcpy(ocp, icp, isize);
 476        *cpp = ocp;
 477        ocp[9] = cs->cs_this;
 478        ocp[0] |= SL_TYPE_UNCOMPRESSED_TCP;
 479        return isize;
 480}
 481
 482
 483int
 484slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)
 485{
 486        register int changes;
 487        long x;
 488        register struct tcphdr *thp;
 489        register struct iphdr *ip;
 490        register struct cstate *cs;
 491        int len, hdrlen;
 492        unsigned char *cp = icp;
 493
 494        /* We've got a compressed packet; read the change byte */
 495        comp->sls_i_compressed++;
 496        if(isize < 3){
 497                comp->sls_i_error++;
 498                return 0;
 499        }
 500        changes = *cp++;
 501        if(changes & NEW_C){
 502                /* Make sure the state index is in range, then grab the state.
 503                 * If we have a good state index, clear the 'discard' flag.
 504                 */
 505                x = *cp++;      /* Read conn index */
 506                if(x < 0 || x > comp->rslot_limit)
 507                        goto bad;
 508
 509                comp->flags &=~ SLF_TOSS;
 510                comp->recv_current = x;
 511        } else {
 512                /* this packet has an implicit state index.  If we've
 513                 * had a line error since the last time we got an
 514                 * explicit state index, we have to toss the packet. */
 515                if(comp->flags & SLF_TOSS){
 516                        comp->sls_i_tossed++;
 517                        return 0;
 518                }
 519        }
 520        cs = &comp->rstate[comp->recv_current];
 521        thp = &cs->cs_tcp;
 522        ip = &cs->cs_ip;
 523
 524        thp->check = *(__sum16 *)cp;
 525        cp += 2;
 526
 527        thp->psh = (changes & TCP_PUSH_BIT) ? 1 : 0;
 528/*
 529 * we can use the same number for the length of the saved header and
 530 * the current one, because the packet wouldn't have been sent
 531 * as compressed unless the options were the same as the previous one
 532 */
 533
 534        hdrlen = ip->ihl * 4 + thp->doff * 4;
 535
 536        switch(changes & SPECIALS_MASK){
 537        case SPECIAL_I:         /* Echoed terminal traffic */
 538                {
 539                register short i;
 540                i = ntohs(ip->tot_len) - hdrlen;
 541                thp->ack_seq = htonl( ntohl(thp->ack_seq) + i);
 542                thp->seq = htonl( ntohl(thp->seq) + i);
 543                }
 544                break;
 545
 546        case SPECIAL_D:                 /* Unidirectional data */
 547                thp->seq = htonl( ntohl(thp->seq) +
 548                                  ntohs(ip->tot_len) - hdrlen);
 549                break;
 550
 551        default:
 552                if(changes & NEW_U){
 553                        thp->urg = 1;
 554                        if((x = decode(&cp)) == -1) {
 555                                goto bad;
 556                        }
 557                        thp->urg_ptr = htons(x);
 558                } else
 559                        thp->urg = 0;
 560                if(changes & NEW_W){
 561                        if((x = decode(&cp)) == -1) {
 562                                goto bad;
 563                        }
 564                        thp->window = htons( ntohs(thp->window) + x);
 565                }
 566                if(changes & NEW_A){
 567                        if((x = decode(&cp)) == -1) {
 568                                goto bad;
 569                        }
 570                        thp->ack_seq = htonl( ntohl(thp->ack_seq) + x);
 571                }
 572                if(changes & NEW_S){
 573                        if((x = decode(&cp)) == -1) {
 574                                goto bad;
 575                        }
 576                        thp->seq = htonl( ntohl(thp->seq) + x);
 577                }
 578                break;
 579        }
 580        if(changes & NEW_I){
 581                if((x = decode(&cp)) == -1) {
 582                        goto bad;
 583                }
 584                ip->id = htons (ntohs (ip->id) + x);
 585        } else
 586                ip->id = htons (ntohs (ip->id) + 1);
 587
 588        /*
 589         * At this point, cp points to the first byte of data in the
 590         * packet.  Put the reconstructed TCP and IP headers back on the
 591         * packet.  Recalculate IP checksum (but not TCP checksum).
 592         */
 593
 594        len = isize - (cp - icp);
 595        if (len < 0)
 596                goto bad;
 597        len += hdrlen;
 598        ip->tot_len = htons(len);
 599        ip->check = 0;
 600
 601        memmove(icp + hdrlen, cp, len - hdrlen);
 602
 603        cp = icp;
 604        memcpy(cp, ip, 20);
 605        cp += 20;
 606
 607        if (ip->ihl > 5) {
 608          memcpy(cp, cs->cs_ipopt, (ip->ihl - 5) * 4);
 609          cp += (ip->ihl - 5) * 4;
 610        }
 611
 612        put_unaligned(ip_fast_csum(icp, ip->ihl),
 613                      &((struct iphdr *)icp)->check);
 614
 615        memcpy(cp, thp, 20);
 616        cp += 20;
 617
 618        if (thp->doff > 5) {
 619          memcpy(cp, cs->cs_tcpopt, ((thp->doff) - 5) * 4);
 620          cp += ((thp->doff) - 5) * 4;
 621        }
 622
 623        return len;
 624bad:
 625        comp->sls_i_error++;
 626        return slhc_toss( comp );
 627}
 628
 629
 630int
 631slhc_remember(struct slcompress *comp, unsigned char *icp, int isize)
 632{
 633        register struct cstate *cs;
 634        unsigned ihl;
 635
 636        unsigned char index;
 637
 638        if(isize < 20) {
 639                /* The packet is shorter than a legal IP header */
 640                comp->sls_i_runt++;
 641                return slhc_toss( comp );
 642        }
 643        /* Peek at the IP header's IHL field to find its length */
 644        ihl = icp[0] & 0xf;
 645        if(ihl < 20 / 4){
 646                /* The IP header length field is too small */
 647                comp->sls_i_runt++;
 648                return slhc_toss( comp );
 649        }
 650        index = icp[9];
 651        icp[9] = IPPROTO_TCP;
 652
 653        if (ip_fast_csum(icp, ihl)) {
 654                /* Bad IP header checksum; discard */
 655                comp->sls_i_badcheck++;
 656                return slhc_toss( comp );
 657        }
 658        if(index > comp->rslot_limit) {
 659                comp->sls_i_error++;
 660                return slhc_toss(comp);
 661        }
 662
 663        /* Update local state */
 664        cs = &comp->rstate[comp->recv_current = index];
 665        comp->flags &=~ SLF_TOSS;
 666        memcpy(&cs->cs_ip,icp,20);
 667        memcpy(&cs->cs_tcp,icp + ihl*4,20);
 668        if (ihl > 5)
 669          memcpy(cs->cs_ipopt, icp + sizeof(struct iphdr), (ihl - 5) * 4);
 670        if (cs->cs_tcp.doff > 5)
 671          memcpy(cs->cs_tcpopt, icp + ihl*4 + sizeof(struct tcphdr), (cs->cs_tcp.doff - 5) * 4);
 672        cs->cs_hsize = ihl*2 + cs->cs_tcp.doff*2;
 673        /* Put headers back on packet
 674         * Neither header checksum is recalculated
 675         */
 676        comp->sls_i_uncompressed++;
 677        return isize;
 678}
 679
 680int
 681slhc_toss(struct slcompress *comp)
 682{
 683        if ( comp == NULLSLCOMPR )
 684                return 0;
 685
 686        comp->flags |= SLF_TOSS;
 687        return 0;
 688}
 689
 690#else /* CONFIG_INET */
 691
 692int
 693slhc_toss(struct slcompress *comp)
 694{
 695  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_toss");
 696  return -EINVAL;
 697}
 698int
 699slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)
 700{
 701  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_uncompress");
 702  return -EINVAL;
 703}
 704int
 705slhc_compress(struct slcompress *comp, unsigned char *icp, int isize,
 706        unsigned char *ocp, unsigned char **cpp, int compress_cid)
 707{
 708  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_compress");
 709  return -EINVAL;
 710}
 711
 712int
 713slhc_remember(struct slcompress *comp, unsigned char *icp, int isize)
 714{
 715  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_remember");
 716  return -EINVAL;
 717}
 718
 719void
 720slhc_free(struct slcompress *comp)
 721{
 722  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_free");
 723}
 724struct slcompress *
 725slhc_init(int rslots, int tslots)
 726{
 727  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_init");
 728  return NULL;
 729}
 730
 731#endif /* CONFIG_INET */
 732
 733/* VJ header compression */
 734EXPORT_SYMBOL(slhc_init);
 735EXPORT_SYMBOL(slhc_free);
 736EXPORT_SYMBOL(slhc_remember);
 737EXPORT_SYMBOL(slhc_compress);
 738EXPORT_SYMBOL(slhc_uncompress);
 739EXPORT_SYMBOL(slhc_toss);
 740
 741MODULE_LICENSE("Dual BSD/GPL");
 742