root/drivers/net/slhc.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. slhc_init
  2. slhc_free
  3. put16
  4. encode
  5. pull16
  6. decode
  7. slhc_compress
  8. slhc_uncompress
  9. slhc_remember
  10. slhc_toss
  11. slhc_i_status
  12. slhc_o_status
  13. init_module
  14. cleanup_module

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

/* [previous][next][first][last][top][bottom][index][help] */