blank.gif (43 bytes)

Church Of The
Swimming Elephant

Search:
A.3 Decompression Connected: An Internet Encyclopedia
A.3 Decompression

Up: Connected: An Internet Encyclopedia
Up: Requests For Comments
Up: RFC 1144
Up: A Sample Implementation
Prev: A.2 Compression
Next: A.4 Initialization

A.3 Decompression

A.3 Decompression

This routine decompresses a received packet. It is called with a pointer to the packet, the packet length and type, and a pointer to the compression state structure for the incoming serial line. It returns a pointer to the resulting packet or zero if there were errors in the incoming packet. If the packet is COMPRESSED_TCP or UNCOMPRESSED_TCP, the compression state will be updated.

The new packet will be constructed in-place. That means that there must be 128 bytes of free space in front of bufp to allow room for the reconstructed IP and TCP headers. The reconstructed packet will be aligned on a 32-bit boundary.

   u_char *
   sl_uncompress_tcp(bufp, len, type, comp)
        u_char *bufp;
        int len;
        u_int type;
        struct slcompress *comp;
   {
        register u_char *cp;
        register u_int hlen, changes;
        register struct tcphdr *th;
        register struct cstate *cs;
        register struct ip *ip;

        switch (type) {

        case TYPE_ERROR:
        default:
             goto bad;

        case TYPE_IP:
             return (bufp);

        case TYPE_UNCOMPRESSED_TCP:
             /*
              * Locate the saved state for this connection.  If the state
              * index is legal, clear the 'discard' flag.
              */
             ip = (struct ip *) bufp;
             if (ip->ip_p >= MAX_STATES)
                  goto bad;

             cs = &comp->rstate[comp->last_recv = ip->ip_p];
             comp->flags &= ~SLF_TOSS;
             /*
              * Restore the IP protocol field then save a copy of this
              * packet header.  (The checksum is zeroed in the copy so we
              * don't have to zero it each time we process a compressed

              * packet.
              */
             ip->ip_p = IPPROTO_TCP;
             hlen = ip->ip_hl;
             hlen += ((struct tcphdr *) & ((int *) ip)[hlen])->th_off;
             hlen <<= 2;
             BCOPY(ip, &cs->cs_ip, hlen);
             cs->cs_ip.ip_sum = 0;
             cs->cs_hlen = hlen;
             return (bufp);

        case TYPE_COMPRESSED_TCP:
             break;
        }
        /* We've got a compressed packet. */
        cp = bufp;
        changes = *cp++;
        if (changes & NEW_C) {
             /*
              * Make sure the state index is in range, then grab the
              * state. If we have a good state index, clear the 'discard'
              * flag.
              */
             if (*cp >= MAX_STATES)
                  goto bad;

             comp->flags &= ~SLF_TOSS;
             comp->last_recv = *cp++;
        } else {
             /*
              * This packet has an implicit state index.  If we've had a
              * line error since the last time we got an explicit state
              * index, we have to toss the packet.
              */
             if (comp->flags & SLF_TOSS)
                  return ((u_char *) 0);
        }
        /*
         * Find the state then fill in the TCP checksum and PUSH bit.
         */
        cs = &comp->rstate[comp->last_recv];
        hlen = cs->cs_ip.ip_hl << 2;
        th = (struct tcphdr *) & ((u_char *) &cs->cs_ip)[hlen];
        th->th_sum = htons((*cp << 8) | cp[1]);
        cp += 2;
        if (changes & TCP_PUSH_BIT)
             th->th_flags |= TH_PUSH;
        else
             th->th_flags &= ~TH_PUSH;

        /*

         * Fix up the state's ack, seq, urg and win fields based on the
         * changemask.
         */
        switch (changes & SPECIALS_MASK) {
        case SPECIAL_I:
             {
             register u_int i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen;
             th->th_ack = htonl(ntohl(th->th_ack) + i);
             th->th_seq = htonl(ntohl(th->th_seq) + i);
             }
             break;

        case SPECIAL_D:
             th->th_seq = htonl(ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len)
                          - cs->cs_hlen);
             break;

        default:
             if (changes & NEW_U) {
                  th->th_flags |= TH_URG;
                  DECODEU(th->th_urp)
             } else
                  th->th_flags &= ~TH_URG;
             if (changes & NEW_W)
                  DECODES(th->th_win)
             if (changes & NEW_A)
                  DECODEL(th->th_ack)
             if (changes & NEW_S)
                  DECODEL(th->th_seq)
             break;
        }
        /* Update the IP ID */
        if (changes & NEW_I)
             DECODES(cs->cs_ip.ip_id)
        else
             cs->cs_ip.ip_id = htons(ntohs(cs->cs_ip.ip_id) + 1);

        /*
         * At this point, cp points to the first byte of data in the packet.
         * If we're not aligned on a 4-byte boundary, copy the data down so
         * the IP & TCP headers will be aligned.  Then back up cp by the
         * TCP/IP header length to make room for the reconstructed header (we
         * assume the packet we were handed has enough space to prepend 128
         * bytes of header).  Adjust the lenth to account for the new header
         * & fill in the IP total length.
         */
        len -= (cp - bufp);
        if (len < 0)
             /*
              * we must have dropped some characters (crc should detect
              * this but the old slip framing won't)

              */
             goto bad;

        if ((int) cp & 3) {
             if (len > 0)
                  OVBCOPY(cp, (int) cp & ~3, len);
             cp = (u_char *) ((int) cp & ~3);
        }
        cp -= cs->cs_hlen;
        len += cs->cs_hlen;
        cs->cs_ip.ip_len = htons(len);
        BCOPY(&cs->cs_ip, cp, cs->cs_hlen);

        /* recompute the ip header checksum */
        {
             register u_short *bp = (u_short *) cp;
             for (changes = 0; hlen > 0; hlen -= 2)
                  changes += *bp++;
             changes = (changes & 0xffff) + (changes >> 16);
             changes = (changes & 0xffff) + (changes >> 16);
             ((struct ip *) cp)->ip_sum = ~changes;
        }
        return (cp);

   bad:
        comp->flags |= SLF_TOSS;
        return ((u_char *) 0);
   }


Next: A.4 Initialization

Connected: An Internet Encyclopedia
A.3 Decompression

Cotse.Net

Protect yourself from cyberstalkers, identity thieves, and those who would snoop on you.
Stop spam from invading your inbox without losing the mail you want. We give you more control over your e-mail than any other service.
Block popups, ads, and malicious scripts while you surf the net through our anonymous proxies.
Participate in Usenet, host your web files, easily send anonymous messages, and more, much more.
All private, all encrypted, all secure, all in an easy to use service, and all for only $5.95 a month!

Service Details

 
.
www.cotse.com
Have you gone to church today?
.
All pages ©1999, 2000, 2001, 2002, 2003 Church of the Swimming Elephant unless otherwise stated
Church of the Swimming Elephant©1999, 2000, 2001, 2002, 2003 Cotse.com.
Cotse.com is a wholly owned subsidiary of Packetderm, LLC.

Packetderm, LLC
210 Park Ave #308
Worcester, MA 01609