⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 compress.c

📁 PPPoE协议在Psos中的实现源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
        comp->last_cs = lcs;
        hlen += th->th_off;
        hlen <<= 2;
        if (hlen > m->m_len)
            return (TYPE_IP);
        goto uncompressed;

    found:
        /*
         * Found it -- move to the front on the connection list.
         */
        if (cs == lastcs)
            comp->last_cs = lcs;
        else {
            lcs->cs_next = cs->cs_next;
            cs->cs_next = lastcs->cs_next;
            lastcs->cs_next = cs;
        }
    }

    /*
     * Make sure that only what we expect to change changed. The first
     * line of the `if' checks the IP protocol version, header length &
     * type of service.  The 2nd line checks the "Don't fragment" bit.
     * The 3rd line checks the time-to-live and protocol (the protocol
     * check is unnecessary but costless).  The 4th line checks the TCP
     * header length.  The 5th line checks IP options, if any.  The 6th
     * line checks TCP options, if any.  If any of these things are
     * different between the previous & current datagram, we send the
     * current datagram `uncompressed'.
     */
    oth = (struct tcphdr *)&((int *)&cs->cs_ip)[hlen];
    deltaS = hlen;
    hlen += th->th_off;
    hlen <<= 2;
    if (hlen > m->m_len)
        return (TYPE_IP);

    if (((U_SHORT *)ip)[0] != ((U_SHORT *)&cs->cs_ip)[0] ||
        ((U_SHORT *)ip)[3] != ((U_SHORT *)&cs->cs_ip)[3] ||
        ((U_SHORT *)ip)[4] != ((U_SHORT *)&cs->cs_ip)[4] ||
        th->th_off != oth->th_off ||
        (deltaS > 5 &&
         BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) ||
        (th->th_off > 5 &&
         BCMP(th + 1, oth + 1, (th->th_off - 5) << 2)))
        goto uncompressed;

    /*
     * Figure out which of the changing fields changed.  The
     * receiver expects changes in the order: urgent, window,
     * ack, seq (the order minimizes the number of temporaries
     * needed in this section of code).
     */
    if (th->th_flags & TH_URG) {
        deltaS = ntohs(th->th_urp);
        ENCODEZ(deltaS);
        changes |= NEW_U;
    } else if (th->th_urp != oth->th_urp)
        /* argh! URG not set but urp changed -- a sensible
         * implementation should never do this but RFC793
         * doesn't prohibit the change so we have to deal
         * with it. */
         goto uncompressed;

    if (deltaS = (U_SHORT)(ntohs(th->th_win) - ntohs(oth->th_win))) {
        ENCODE(deltaS);
        changes |= NEW_W;
    }

    if (deltaA = ntohl(th->th_ack) - ntohl(oth->th_ack)) {
        if (deltaA > 0xffff)
            goto uncompressed;
        ENCODE(deltaA);
        changes |= NEW_A;
    }

    if (deltaS = ntohl(th->th_seq) - ntohl(oth->th_seq)) {
        if (deltaS > 0xffff)
            goto uncompressed;
        ENCODE(deltaS);
        changes |= NEW_S;
    }

    switch(changes) {

    case 0:
        /*
         * Nothing changed. If this packet contains data and the
         * last one didn't, this is probably a data packet following
         * an ack (normal on an interactive connection) and we send
         * it compressed.  Otherwise it's probably a retransmit,
         * retransmitted ack or window probe.  Send it uncompressed
         * in case the other side missed the compressed version.
         */
        if (ip->ip_len != cs->cs_ip.ip_len &&
            ntohs(cs->cs_ip.ip_len) == hlen)
            break;

        /* (fall through) */

    case SPECIAL_I:
    case SPECIAL_D:
        /*
         * actual changes match one of our special case encodings --
         * send packet uncompressed.
         */
        goto uncompressed;

    case NEW_S|NEW_A:
        if (deltaS == deltaA &&
            deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {
            /* special case for echoed terminal traffic */
            changes = SPECIAL_I;
            cp = new_seq;
        }
        break;

    case NEW_S:
        if (deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {
            /* special case for data xfer */
            changes = SPECIAL_D;
            cp = new_seq;
        }
        break;
    }

    deltaS = ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id);
    if (deltaS != 1) {
        ENCODEZ(deltaS);
        changes |= NEW_I;
    }
    if (th->th_flags & TH_PUSH)
        changes |= TCP_PUSH_BIT;
    /*
     * Grab the cksum before we overwrite it below.  Then update our
     * state with this packet's header.
     */
    deltaA = ntohs(th->th_sum);
    BCOPY(ip, &cs->cs_ip, hlen);

    /*
     * We want to use the original packet as our compressed packet.
     * (cp - new_seq) is the number of bytes we need for compressed
     * sequence numbers.  In addition we need one byte for the change
     * mask, one for the connection id and two for the tcp checksum.
     * So, (cp - new_seq) + 4 bytes of header are needed.  hlen is how
     * many bytes of the original packet to toss so subtract the two to
     * get the new packet size.
     */
    deltaS = cp - new_seq;
    cp = (U_CHAR *)ip;
    if (compress_cid == 0 || comp->last_xmit != cs->cs_id) {
        comp->last_xmit = cs->cs_id;
        hlen -= deltaS + 4;
        cp += hlen;
        *cp++ = changes | NEW_C;
        *cp++ = cs->cs_id;
    } else {
        hlen -= deltaS + 3;
        cp += hlen;
        *cp++ = changes;
    }
    m->m_len -= hlen;
    m->m_off += hlen;
    *cp++ = deltaA >> 8;
    *cp++ = deltaA;
    BCOPY(new_seq, cp, deltaS);
    INCR(sls_compressed);
    return (TYPE_COMPRESSED_TCP);

    /*
     * Update connection state cs & send uncompressed packet ('uncompressed'
     * means a regular ip/tcp packet but with the 'conversation id' we hope
     * to use on future compressed packets in the protocol field).
     */
uncompressed:
    BCOPY(ip, &cs->cs_ip, hlen);
    ip->ip_p = cs->cs_id;
    comp->last_xmit = cs->cs_id;
    return (TYPE_UNCOMPRESSED_TCP);
}


int
sl_uncompress_tcp(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_UNCOMPRESSED_TCP:
        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;
        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;
        INCR(sls_uncompressedin);
        return (len);

    default:
        goto bad;

    case TYPE_COMPRESSED_TCP:
        break;
    }
    /* We've got a compressed packet. */
    INCR(sls_compressedin);
    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) {
            INCR(sls_tossed);
            return (0);
        }
    }
    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;

    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;
    }
    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 length 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) {
      U_CHAR *tmp = cp;

        if (len > 0)
            (void) ovbcopy(cp, (U_CHAR */*-mz*/)((int)cp &~ 3), len);
        tmp = (U_CHAR *)((int)cp &~ 3);  /* stupid mri compiler forces
                                            breaking up this line */
        cp = tmp;
    }
    cp -= cs->cs_hlen;
    len += cs->cs_hlen;
    cs->cs_ip.ip_len = htons(len);
    BCOPY(&cs->cs_ip, cp, cs->cs_hlen);
    *bufp = cp;

    /* 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 (len);
bad:
    comp->flags |= SLF_TOSS;
    INCR(sls_errorin);
    return (0);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -