Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Routines to compress and uncompress tcp packets (for transmission
0003  * over low speed serial lines).
0004  *
0005  * Copyright (c) 1989 Regents of the University of California.
0006  * All rights reserved.
0007  *
0008  * Redistribution and use in source and binary forms are permitted
0009  * provided that the above copyright notice and this paragraph are
0010  * duplicated in all such forms and that any documentation,
0011  * advertising materials, and other materials related to such
0012  * distribution and use acknowledge that the software was developed
0013  * by the University of California, Berkeley.  The name of the
0014  * University may not be used to endorse or promote products derived
0015  * from this software without specific prior written permission.
0016  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
0017  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
0018  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
0019  *
0020  *  Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
0021  *  - Initial distribution.
0022  *
0023  *
0024  * modified for KA9Q Internet Software Package by
0025  * Katie Stevens (dkstevens@ucdavis.edu)
0026  * University of California, Davis
0027  * Computing Services
0028  *  - 01-31-90  initial adaptation (from 1.19)
0029  *  PPP.05  02-15-90 [ks]
0030  *  PPP.08  05-02-90 [ks]   use PPP protocol field to signal compression
0031  *  PPP.15  09-90    [ks]   improve mbuf handling
0032  *  PPP.16  11-02    [karn] substantially rewritten to use NOS facilities
0033  *
0034  *  - Feb 1991  Bill_Simpson@um.cc.umich.edu
0035  *          variable number of conversation slots
0036  *          allow zero or one slots
0037  *          separate routines
0038  *          status display
0039  *  - Jul 1994  Dmitry Gorodchanin
0040  *          Fixes for memory leaks.
0041  *      - Oct 1994      Dmitry Gorodchanin
0042  *                      Modularization.
0043  *  - Jan 1995  Bjorn Ekwall
0044  *          Use ip_fast_csum from ip.h
0045  *  - July 1995 Christos A. Polyzols
0046  *          Spotted bug in tcp option checking
0047  *
0048  *
0049  *  This module is a difficult issue. It's clearly inet code but it's also clearly
0050  *  driver code belonging close to PPP and SLIP
0051  */
0052 
0053 #include <linux/module.h>
0054 #include <linux/slab.h>
0055 #include <linux/types.h>
0056 #include <linux/string.h>
0057 #include <linux/errno.h>
0058 #include <linux/kernel.h>
0059 #include <net/slhc_vj.h>
0060 
0061 #ifdef CONFIG_INET
0062 /* Entire module is for IP only */
0063 #include <linux/mm.h>
0064 #include <linux/socket.h>
0065 #include <linux/sockios.h>
0066 #include <linux/termios.h>
0067 #include <linux/in.h>
0068 #include <linux/fcntl.h>
0069 #include <linux/inet.h>
0070 #include <linux/netdevice.h>
0071 #include <net/ip.h>
0072 #include <net/protocol.h>
0073 #include <net/icmp.h>
0074 #include <net/tcp.h>
0075 #include <linux/skbuff.h>
0076 #include <net/sock.h>
0077 #include <linux/timer.h>
0078 #include <linux/uaccess.h>
0079 #include <net/checksum.h>
0080 #include <asm/unaligned.h>
0081 
0082 static unsigned char *encode(unsigned char *cp, unsigned short n);
0083 static long decode(unsigned char **cpp);
0084 static unsigned char * put16(unsigned char *cp, unsigned short x);
0085 static unsigned short pull16(unsigned char **cpp);
0086 
0087 /* Allocate compression data structure
0088  *  slots must be in range 0 to 255 (zero meaning no compression)
0089  * Returns pointer to structure or ERR_PTR() on error.
0090  */
0091 struct slcompress *
0092 slhc_init(int rslots, int tslots)
0093 {
0094     short i;
0095     struct cstate *ts;
0096     struct slcompress *comp;
0097 
0098     if (rslots < 0 || rslots > 255 || tslots < 0 || tslots > 255)
0099         return ERR_PTR(-EINVAL);
0100 
0101     comp = kzalloc(sizeof(struct slcompress), GFP_KERNEL);
0102     if (! comp)
0103         goto out_fail;
0104 
0105     if (rslots > 0) {
0106         size_t rsize = rslots * sizeof(struct cstate);
0107         comp->rstate = kzalloc(rsize, GFP_KERNEL);
0108         if (! comp->rstate)
0109             goto out_free;
0110         comp->rslot_limit = rslots - 1;
0111     }
0112 
0113     if (tslots > 0) {
0114         size_t tsize = tslots * sizeof(struct cstate);
0115         comp->tstate = kzalloc(tsize, GFP_KERNEL);
0116         if (! comp->tstate)
0117             goto out_free2;
0118         comp->tslot_limit = tslots - 1;
0119     }
0120 
0121     comp->xmit_oldest = 0;
0122     comp->xmit_current = 255;
0123     comp->recv_current = 255;
0124     /*
0125      * don't accept any packets with implicit index until we get
0126      * one with an explicit index.  Otherwise the uncompress code
0127      * will try to use connection 255, which is almost certainly
0128      * out of range
0129      */
0130     comp->flags |= SLF_TOSS;
0131 
0132     if ( tslots > 0 ) {
0133         ts = comp->tstate;
0134         for(i = comp->tslot_limit; i > 0; --i){
0135             ts[i].cs_this = i;
0136             ts[i].next = &(ts[i - 1]);
0137         }
0138         ts[0].next = &(ts[comp->tslot_limit]);
0139         ts[0].cs_this = 0;
0140     }
0141     return comp;
0142 
0143 out_free2:
0144     kfree(comp->rstate);
0145 out_free:
0146     kfree(comp);
0147 out_fail:
0148     return ERR_PTR(-ENOMEM);
0149 }
0150 
0151 
0152 /* Free a compression data structure */
0153 void
0154 slhc_free(struct slcompress *comp)
0155 {
0156     if ( IS_ERR_OR_NULL(comp) )
0157         return;
0158 
0159     if ( comp->tstate != NULLSLSTATE )
0160         kfree( comp->tstate );
0161 
0162     if ( comp->rstate != NULLSLSTATE )
0163         kfree( comp->rstate );
0164 
0165     kfree( comp );
0166 }
0167 
0168 
0169 /* Put a short in host order into a char array in network order */
0170 static inline unsigned char *
0171 put16(unsigned char *cp, unsigned short x)
0172 {
0173     *cp++ = x >> 8;
0174     *cp++ = x;
0175 
0176     return cp;
0177 }
0178 
0179 
0180 /* Encode a number */
0181 static unsigned char *
0182 encode(unsigned char *cp, unsigned short n)
0183 {
0184     if(n >= 256 || n == 0){
0185         *cp++ = 0;
0186         cp = put16(cp,n);
0187     } else {
0188         *cp++ = n;
0189     }
0190     return cp;
0191 }
0192 
0193 /* Pull a 16-bit integer in host order from buffer in network byte order */
0194 static unsigned short
0195 pull16(unsigned char **cpp)
0196 {
0197     short rval;
0198 
0199     rval = *(*cpp)++;
0200     rval <<= 8;
0201     rval |= *(*cpp)++;
0202     return rval;
0203 }
0204 
0205 /* Decode a number */
0206 static long
0207 decode(unsigned char **cpp)
0208 {
0209     int x;
0210 
0211     x = *(*cpp)++;
0212     if(x == 0){
0213         return pull16(cpp) & 0xffff;    /* pull16 returns -1 on error */
0214     } else {
0215         return x & 0xff;        /* -1 if PULLCHAR returned error */
0216     }
0217 }
0218 
0219 /*
0220  * icp and isize are the original packet.
0221  * ocp is a place to put a copy if necessary.
0222  * cpp is initially a pointer to icp.  If the copy is used,
0223  *    change it to ocp.
0224  */
0225 
0226 int
0227 slhc_compress(struct slcompress *comp, unsigned char *icp, int isize,
0228     unsigned char *ocp, unsigned char **cpp, int compress_cid)
0229 {
0230     struct cstate *ocs = &(comp->tstate[comp->xmit_oldest]);
0231     struct cstate *lcs = ocs;
0232     struct cstate *cs = lcs->next;
0233     unsigned long deltaS, deltaA;
0234     short changes = 0;
0235     int nlen, hlen;
0236     unsigned char new_seq[16];
0237     unsigned char *cp = new_seq;
0238     struct iphdr *ip;
0239     struct tcphdr *th, *oth;
0240     __sum16 csum;
0241 
0242 
0243     /*
0244      *  Don't play with runt packets.
0245      */
0246 
0247     if(isize<sizeof(struct iphdr))
0248         return isize;
0249 
0250     ip = (struct iphdr *) icp;
0251     if (ip->version != 4 || ip->ihl < 5)
0252         return isize;
0253 
0254     /* Bail if this packet isn't TCP, or is an IP fragment */
0255     if (ip->protocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x3fff)) {
0256         /* Send as regular IP */
0257         if(ip->protocol != IPPROTO_TCP)
0258             comp->sls_o_nontcp++;
0259         else
0260             comp->sls_o_tcp++;
0261         return isize;
0262     }
0263     nlen = ip->ihl * 4;
0264     if (isize < nlen + sizeof(*th))
0265         return isize;
0266 
0267     th = (struct tcphdr *)(icp + nlen);
0268     if (th->doff < sizeof(struct tcphdr) / 4)
0269         return isize;
0270     hlen = nlen + th->doff * 4;
0271 
0272     /*  Bail if the TCP packet isn't `compressible' (i.e., ACK isn't set or
0273      *  some other control bit is set). Also uncompressible if
0274      *  it's a runt.
0275      */
0276     if(hlen > isize || th->syn || th->fin || th->rst ||
0277         ! (th->ack)){
0278         /* TCP connection stuff; send as regular IP */
0279         comp->sls_o_tcp++;
0280         return isize;
0281     }
0282     /*
0283      * Packet is compressible -- we're going to send either a
0284      * COMPRESSED_TCP or UNCOMPRESSED_TCP packet.  Either way,
0285      * we need to locate (or create) the connection state.
0286      *
0287      * States are kept in a circularly linked list with
0288      * xmit_oldest pointing to the end of the list.  The
0289      * list is kept in lru order by moving a state to the
0290      * head of the list whenever it is referenced.  Since
0291      * the list is short and, empirically, the connection
0292      * we want is almost always near the front, we locate
0293      * states via linear search.  If we don't find a state
0294      * for the datagram, the oldest state is (re-)used.
0295      */
0296     for ( ; ; ) {
0297         if( ip->saddr == cs->cs_ip.saddr
0298          && ip->daddr == cs->cs_ip.daddr
0299          && th->source == cs->cs_tcp.source
0300          && th->dest == cs->cs_tcp.dest)
0301             goto found;
0302 
0303         /* if current equal oldest, at end of list */
0304         if ( cs == ocs )
0305             break;
0306         lcs = cs;
0307         cs = cs->next;
0308         comp->sls_o_searches++;
0309     }
0310     /*
0311      * Didn't find it -- re-use oldest cstate.  Send an
0312      * uncompressed packet that tells the other side what
0313      * connection number we're using for this conversation.
0314      *
0315      * Note that since the state list is circular, the oldest
0316      * state points to the newest and we only need to set
0317      * xmit_oldest to update the lru linkage.
0318      */
0319     comp->sls_o_misses++;
0320     comp->xmit_oldest = lcs->cs_this;
0321     goto uncompressed;
0322 
0323 found:
0324     /*
0325      * Found it -- move to the front on the connection list.
0326      */
0327     if(lcs == ocs) {
0328         /* found at most recently used */
0329     } else if (cs == ocs) {
0330         /* found at least recently used */
0331         comp->xmit_oldest = lcs->cs_this;
0332     } else {
0333         /* more than 2 elements */
0334         lcs->next = cs->next;
0335         cs->next = ocs->next;
0336         ocs->next = cs;
0337     }
0338 
0339     /*
0340      * Make sure that only what we expect to change changed.
0341      * Check the following:
0342      * IP protocol version, header length & type of service.
0343      * The "Don't fragment" bit.
0344      * The time-to-live field.
0345      * The TCP header length.
0346      * IP options, if any.
0347      * TCP options, if any.
0348      * If any of these things are different between the previous &
0349      * current datagram, we send the current datagram `uncompressed'.
0350      */
0351     oth = &cs->cs_tcp;
0352 
0353     if(ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl
0354      || ip->tos != cs->cs_ip.tos
0355      || (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000))
0356      || ip->ttl != cs->cs_ip.ttl
0357      || th->doff != cs->cs_tcp.doff
0358      || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0)
0359      || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)){
0360         goto uncompressed;
0361     }
0362 
0363     /*
0364      * Figure out which of the changing fields changed.  The
0365      * receiver expects changes in the order: urgent, window,
0366      * ack, seq (the order minimizes the number of temporaries
0367      * needed in this section of code).
0368      */
0369     if(th->urg){
0370         deltaS = ntohs(th->urg_ptr);
0371         cp = encode(cp,deltaS);
0372         changes |= NEW_U;
0373     } else if(th->urg_ptr != oth->urg_ptr){
0374         /* argh! URG not set but urp changed -- a sensible
0375          * implementation should never do this but RFC793
0376          * doesn't prohibit the change so we have to deal
0377          * with it. */
0378         goto uncompressed;
0379     }
0380     if((deltaS = ntohs(th->window) - ntohs(oth->window)) != 0){
0381         cp = encode(cp,deltaS);
0382         changes |= NEW_W;
0383     }
0384     if((deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L){
0385         if(deltaA > 0x0000ffff)
0386             goto uncompressed;
0387         cp = encode(cp,deltaA);
0388         changes |= NEW_A;
0389     }
0390     if((deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L){
0391         if(deltaS > 0x0000ffff)
0392             goto uncompressed;
0393         cp = encode(cp,deltaS);
0394         changes |= NEW_S;
0395     }
0396 
0397     switch(changes){
0398     case 0: /* Nothing changed. If this packet contains data and the
0399          * last one didn't, this is probably a data packet following
0400          * an ack (normal on an interactive connection) and we send
0401          * it compressed.  Otherwise it's probably a retransmit,
0402          * retransmitted ack or window probe.  Send it uncompressed
0403          * in case the other side missed the compressed version.
0404          */
0405         if(ip->tot_len != cs->cs_ip.tot_len &&
0406            ntohs(cs->cs_ip.tot_len) == hlen)
0407             break;
0408         goto uncompressed;
0409     case SPECIAL_I:
0410     case SPECIAL_D:
0411         /* actual changes match one of our special case encodings --
0412          * send packet uncompressed.
0413          */
0414         goto uncompressed;
0415     case NEW_S|NEW_A:
0416         if(deltaS == deltaA &&
0417             deltaS == ntohs(cs->cs_ip.tot_len) - hlen){
0418             /* special case for echoed terminal traffic */
0419             changes = SPECIAL_I;
0420             cp = new_seq;
0421         }
0422         break;
0423     case NEW_S:
0424         if(deltaS == ntohs(cs->cs_ip.tot_len) - hlen){
0425             /* special case for data xfer */
0426             changes = SPECIAL_D;
0427             cp = new_seq;
0428         }
0429         break;
0430     }
0431     deltaS = ntohs(ip->id) - ntohs(cs->cs_ip.id);
0432     if(deltaS != 1){
0433         cp = encode(cp,deltaS);
0434         changes |= NEW_I;
0435     }
0436     if(th->psh)
0437         changes |= TCP_PUSH_BIT;
0438     /* Grab the cksum before we overwrite it below.  Then update our
0439      * state with this packet's header.
0440      */
0441     csum = th->check;
0442     memcpy(&cs->cs_ip,ip,20);
0443     memcpy(&cs->cs_tcp,th,20);
0444     /* We want to use the original packet as our compressed packet.
0445      * (cp - new_seq) is the number of bytes we need for compressed
0446      * sequence numbers.  In addition we need one byte for the change
0447      * mask, one for the connection id and two for the tcp checksum.
0448      * So, (cp - new_seq) + 4 bytes of header are needed.
0449      */
0450     deltaS = cp - new_seq;
0451     if(compress_cid == 0 || comp->xmit_current != cs->cs_this){
0452         cp = ocp;
0453         *cpp = ocp;
0454         *cp++ = changes | NEW_C;
0455         *cp++ = cs->cs_this;
0456         comp->xmit_current = cs->cs_this;
0457     } else {
0458         cp = ocp;
0459         *cpp = ocp;
0460         *cp++ = changes;
0461     }
0462     *(__sum16 *)cp = csum;
0463     cp += 2;
0464 /* deltaS is now the size of the change section of the compressed header */
0465     memcpy(cp,new_seq,deltaS);  /* Write list of deltas */
0466     memcpy(cp+deltaS,icp+hlen,isize-hlen);
0467     comp->sls_o_compressed++;
0468     ocp[0] |= SL_TYPE_COMPRESSED_TCP;
0469     return isize - hlen + deltaS + (cp - ocp);
0470 
0471     /* Update connection state cs & send uncompressed packet (i.e.,
0472      * a regular ip/tcp packet but with the 'conversation id' we hope
0473      * to use on future compressed packets in the protocol field).
0474      */
0475 uncompressed:
0476     memcpy(&cs->cs_ip,ip,20);
0477     memcpy(&cs->cs_tcp,th,20);
0478     if (ip->ihl > 5)
0479       memcpy(cs->cs_ipopt, ip+1, ((ip->ihl) - 5) * 4);
0480     if (th->doff > 5)
0481       memcpy(cs->cs_tcpopt, th+1, ((th->doff) - 5) * 4);
0482     comp->xmit_current = cs->cs_this;
0483     comp->sls_o_uncompressed++;
0484     memcpy(ocp, icp, isize);
0485     *cpp = ocp;
0486     ocp[9] = cs->cs_this;
0487     ocp[0] |= SL_TYPE_UNCOMPRESSED_TCP;
0488     return isize;
0489 }
0490 
0491 
0492 int
0493 slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)
0494 {
0495     int changes;
0496     long x;
0497     struct tcphdr *thp;
0498     struct iphdr *ip;
0499     struct cstate *cs;
0500     int len, hdrlen;
0501     unsigned char *cp = icp;
0502 
0503     /* We've got a compressed packet; read the change byte */
0504     comp->sls_i_compressed++;
0505     if(isize < 3){
0506         comp->sls_i_error++;
0507         return 0;
0508     }
0509     changes = *cp++;
0510     if(changes & NEW_C){
0511         /* Make sure the state index is in range, then grab the state.
0512          * If we have a good state index, clear the 'discard' flag.
0513          */
0514         x = *cp++;  /* Read conn index */
0515         if(x < 0 || x > comp->rslot_limit)
0516             goto bad;
0517 
0518         /* Check if the cstate is initialized */
0519         if (!comp->rstate[x].initialized)
0520             goto bad;
0521 
0522         comp->flags &=~ SLF_TOSS;
0523         comp->recv_current = x;
0524     } else {
0525         /* this packet has an implicit state index.  If we've
0526          * had a line error since the last time we got an
0527          * explicit state index, we have to toss the packet. */
0528         if(comp->flags & SLF_TOSS){
0529             comp->sls_i_tossed++;
0530             return 0;
0531         }
0532     }
0533     cs = &comp->rstate[comp->recv_current];
0534     thp = &cs->cs_tcp;
0535     ip = &cs->cs_ip;
0536 
0537     thp->check = *(__sum16 *)cp;
0538     cp += 2;
0539 
0540     thp->psh = (changes & TCP_PUSH_BIT) ? 1 : 0;
0541 /*
0542  * we can use the same number for the length of the saved header and
0543  * the current one, because the packet wouldn't have been sent
0544  * as compressed unless the options were the same as the previous one
0545  */
0546 
0547     hdrlen = ip->ihl * 4 + thp->doff * 4;
0548 
0549     switch(changes & SPECIALS_MASK){
0550     case SPECIAL_I:     /* Echoed terminal traffic */
0551         {
0552         short i;
0553         i = ntohs(ip->tot_len) - hdrlen;
0554         thp->ack_seq = htonl( ntohl(thp->ack_seq) + i);
0555         thp->seq = htonl( ntohl(thp->seq) + i);
0556         }
0557         break;
0558 
0559     case SPECIAL_D:         /* Unidirectional data */
0560         thp->seq = htonl( ntohl(thp->seq) +
0561                   ntohs(ip->tot_len) - hdrlen);
0562         break;
0563 
0564     default:
0565         if(changes & NEW_U){
0566             thp->urg = 1;
0567             if((x = decode(&cp)) == -1) {
0568                 goto bad;
0569             }
0570             thp->urg_ptr = htons(x);
0571         } else
0572             thp->urg = 0;
0573         if(changes & NEW_W){
0574             if((x = decode(&cp)) == -1) {
0575                 goto bad;
0576             }
0577             thp->window = htons( ntohs(thp->window) + x);
0578         }
0579         if(changes & NEW_A){
0580             if((x = decode(&cp)) == -1) {
0581                 goto bad;
0582             }
0583             thp->ack_seq = htonl( ntohl(thp->ack_seq) + x);
0584         }
0585         if(changes & NEW_S){
0586             if((x = decode(&cp)) == -1) {
0587                 goto bad;
0588             }
0589             thp->seq = htonl( ntohl(thp->seq) + x);
0590         }
0591         break;
0592     }
0593     if(changes & NEW_I){
0594         if((x = decode(&cp)) == -1) {
0595             goto bad;
0596         }
0597         ip->id = htons (ntohs (ip->id) + x);
0598     } else
0599         ip->id = htons (ntohs (ip->id) + 1);
0600 
0601     /*
0602      * At this point, cp points to the first byte of data in the
0603      * packet.  Put the reconstructed TCP and IP headers back on the
0604      * packet.  Recalculate IP checksum (but not TCP checksum).
0605      */
0606 
0607     len = isize - (cp - icp);
0608     if (len < 0)
0609         goto bad;
0610     len += hdrlen;
0611     ip->tot_len = htons(len);
0612     ip->check = 0;
0613 
0614     memmove(icp + hdrlen, cp, len - hdrlen);
0615 
0616     cp = icp;
0617     memcpy(cp, ip, 20);
0618     cp += 20;
0619 
0620     if (ip->ihl > 5) {
0621       memcpy(cp, cs->cs_ipopt, (ip->ihl - 5) * 4);
0622       cp += (ip->ihl - 5) * 4;
0623     }
0624 
0625     put_unaligned(ip_fast_csum(icp, ip->ihl),
0626               &((struct iphdr *)icp)->check);
0627 
0628     memcpy(cp, thp, 20);
0629     cp += 20;
0630 
0631     if (thp->doff > 5) {
0632       memcpy(cp, cs->cs_tcpopt, ((thp->doff) - 5) * 4);
0633       cp += ((thp->doff) - 5) * 4;
0634     }
0635 
0636     return len;
0637 bad:
0638     comp->sls_i_error++;
0639     return slhc_toss( comp );
0640 }
0641 
0642 
0643 int
0644 slhc_remember(struct slcompress *comp, unsigned char *icp, int isize)
0645 {
0646     struct cstate *cs;
0647     unsigned ihl;
0648 
0649     unsigned char index;
0650 
0651     if(isize < 20) {
0652         /* The packet is shorter than a legal IP header */
0653         comp->sls_i_runt++;
0654         return slhc_toss( comp );
0655     }
0656     /* Peek at the IP header's IHL field to find its length */
0657     ihl = icp[0] & 0xf;
0658     if(ihl < 20 / 4){
0659         /* The IP header length field is too small */
0660         comp->sls_i_runt++;
0661         return slhc_toss( comp );
0662     }
0663     index = icp[9];
0664     icp[9] = IPPROTO_TCP;
0665 
0666     if (ip_fast_csum(icp, ihl)) {
0667         /* Bad IP header checksum; discard */
0668         comp->sls_i_badcheck++;
0669         return slhc_toss( comp );
0670     }
0671     if(index > comp->rslot_limit) {
0672         comp->sls_i_error++;
0673         return slhc_toss(comp);
0674     }
0675 
0676     /* Update local state */
0677     cs = &comp->rstate[comp->recv_current = index];
0678     comp->flags &=~ SLF_TOSS;
0679     memcpy(&cs->cs_ip,icp,20);
0680     memcpy(&cs->cs_tcp,icp + ihl*4,20);
0681     if (ihl > 5)
0682       memcpy(cs->cs_ipopt, icp + sizeof(struct iphdr), (ihl - 5) * 4);
0683     if (cs->cs_tcp.doff > 5)
0684       memcpy(cs->cs_tcpopt, icp + ihl*4 + sizeof(struct tcphdr), (cs->cs_tcp.doff - 5) * 4);
0685     cs->cs_hsize = ihl*2 + cs->cs_tcp.doff*2;
0686     cs->initialized = true;
0687     /* Put headers back on packet
0688      * Neither header checksum is recalculated
0689      */
0690     comp->sls_i_uncompressed++;
0691     return isize;
0692 }
0693 
0694 int
0695 slhc_toss(struct slcompress *comp)
0696 {
0697     if ( comp == NULLSLCOMPR )
0698         return 0;
0699 
0700     comp->flags |= SLF_TOSS;
0701     return 0;
0702 }
0703 
0704 #else /* CONFIG_INET */
0705 
0706 int
0707 slhc_toss(struct slcompress *comp)
0708 {
0709   printk(KERN_DEBUG "Called IP function on non IP-system: slhc_toss");
0710   return -EINVAL;
0711 }
0712 int
0713 slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)
0714 {
0715   printk(KERN_DEBUG "Called IP function on non IP-system: slhc_uncompress");
0716   return -EINVAL;
0717 }
0718 int
0719 slhc_compress(struct slcompress *comp, unsigned char *icp, int isize,
0720     unsigned char *ocp, unsigned char **cpp, int compress_cid)
0721 {
0722   printk(KERN_DEBUG "Called IP function on non IP-system: slhc_compress");
0723   return -EINVAL;
0724 }
0725 
0726 int
0727 slhc_remember(struct slcompress *comp, unsigned char *icp, int isize)
0728 {
0729   printk(KERN_DEBUG "Called IP function on non IP-system: slhc_remember");
0730   return -EINVAL;
0731 }
0732 
0733 void
0734 slhc_free(struct slcompress *comp)
0735 {
0736   printk(KERN_DEBUG "Called IP function on non IP-system: slhc_free");
0737 }
0738 struct slcompress *
0739 slhc_init(int rslots, int tslots)
0740 {
0741   printk(KERN_DEBUG "Called IP function on non IP-system: slhc_init");
0742   return NULL;
0743 }
0744 
0745 #endif /* CONFIG_INET */
0746 
0747 /* VJ header compression */
0748 EXPORT_SYMBOL(slhc_init);
0749 EXPORT_SYMBOL(slhc_free);
0750 EXPORT_SYMBOL(slhc_remember);
0751 EXPORT_SYMBOL(slhc_compress);
0752 EXPORT_SYMBOL(slhc_uncompress);
0753 EXPORT_SYMBOL(slhc_toss);
0754 
0755 MODULE_LICENSE("Dual BSD/GPL");