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