📄 vj.c
字号:
* actual changes match one of our special case encodings -- * send packet uncompressed. */ goto uncompressed; case NEW_S|NEW_A: if (deltaS == deltaA && deltaS == ntohs(IPH_LEN(&cs->cs_ip)) - hlen) { /* special case for echoed terminal traffic */ changes = SPECIAL_I; cp = new_seq; } break; case NEW_S: if (deltaS == ntohs(IPH_LEN(&cs->cs_ip)) - hlen) { /* special case for data xfer */ changes = SPECIAL_D; cp = new_seq; } break; } deltaS = (u_short)(ntohs(IPH_ID(ip)) - ntohs(IPH_ID(&cs->cs_ip))); if (deltaS != 1) { ENCODEZ(deltaS); changes |= NEW_I; } if (TCPH_FLAGS(th) & TCP_PSH) { changes |= TCP_PUSH_BIT; } /* * Grab the cksum before we overwrite it below. Then update our * state with this packet's header. */ deltaA = ntohs(th->chksum); 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 = (u_short)(cp - new_seq); if (!comp->compressSlot || comp->last_xmit != cs->cs_id) { comp->last_xmit = cs->cs_id; hlen -= deltaS + 4; if(pbuf_header(pb, -hlen)){ /* Can we cope with this failing? Just assert for now */ LWIP_ASSERT("pbuf_header failed\n", 0); } cp = (u_char *)pb->payload; *cp++ = (u_char)(changes | NEW_C); *cp++ = cs->cs_id; } else { hlen -= deltaS + 3; if(pbuf_header(pb, -hlen)) { /* Can we cope with this failing? Just assert for now */ LWIP_ASSERT("pbuf_header failed\n", 0); } cp = (u_char *)pb->payload; *cp++ = (u_char)changes; } *cp++ = (u_char)(deltaA >> 8); *cp++ = (u_char)deltaA; BCOPY(new_seq, cp, deltaS); INCR(vjs_compressed); return (TYPE_COMPRESSED_TCP); /* * Update connection state cs & send uncompressed packet (that is, * 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); IPH_PROTO_SET(ip, cs->cs_id); comp->last_xmit = cs->cs_id; return (TYPE_UNCOMPRESSED_TCP);}/* * Called when we may have missed a packet. */voidvj_uncompress_err(struct vjcompress *comp){ comp->flags |= VJF_TOSS; INCR(vjs_errorin);}/* * "Uncompress" a packet of type TYPE_UNCOMPRESSED_TCP. * Return 0 on success, -1 on failure. */intvj_uncompress_uncomp(struct pbuf *nb, struct vjcompress *comp){ register u_int hlen; register struct cstate *cs; register struct ip_hdr *ip; ip = (struct ip_hdr *)nb->payload; hlen = IPH_HL(ip) << 2; if (IPH_PROTO(ip) >= MAX_SLOTS || hlen + sizeof(struct tcp_hdr) > nb->len || (hlen += TCPH_OFFSET(((struct tcp_hdr *)&((char *)ip)[hlen])) << 2) > nb->len || hlen > MAX_HDR) { PPPDEBUG(LOG_INFO, ("vj_uncompress_uncomp: bad cid=%d, hlen=%d buflen=%d\n", IPH_PROTO(ip), hlen, nb->len)); comp->flags |= VJF_TOSS; INCR(vjs_errorin); return -1; } cs = &comp->rstate[comp->last_recv = IPH_PROTO(ip)]; comp->flags &=~ VJF_TOSS; IPH_PROTO_SET(ip, IP_PROTO_TCP); BCOPY(ip, &cs->cs_ip, hlen); cs->cs_hlen = (u_short)hlen; INCR(vjs_uncompressedin); return 0;}/* * Uncompress a packet of type TYPE_COMPRESSED_TCP. * The packet is composed of a buffer chain and the first buffer * must contain an accurate chain length. * The first buffer must include the entire compressed TCP/IP header. * This procedure replaces the compressed header with the uncompressed * header and returns the length of the VJ header. */intvj_uncompress_tcp(struct pbuf **nb, struct vjcompress *comp){ u_char *cp; struct tcp_hdr *th; struct cstate *cs; u_short *bp; struct pbuf *n0 = *nb; u32_t tmp; u_int vjlen, hlen, changes; INCR(vjs_compressedin); cp = (u_char *)n0->payload; 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_SLOTS) { PPPDEBUG(LOG_INFO, ("vj_uncompress_tcp: bad cid=%d\n", *cp)); goto bad; } comp->flags &=~ VJF_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 & VJF_TOSS) { PPPDEBUG(LOG_INFO, ("vj_uncompress_tcp: tossing\n")); INCR(vjs_tossed); return (-1); } } cs = &comp->rstate[comp->last_recv]; hlen = IPH_HL(&cs->cs_ip) << 2; th = (struct tcp_hdr *)&((u_char *)&cs->cs_ip)[hlen]; th->chksum = htons((*cp << 8) | cp[1]); cp += 2; if (changes & TCP_PUSH_BIT) { TCPH_SET_FLAG(th, TCP_PSH); } else { TCPH_UNSET_FLAG(th, TCP_PSH); } switch (changes & SPECIALS_MASK) { case SPECIAL_I: { register u32_t i = ntohs(IPH_LEN(&cs->cs_ip)) - cs->cs_hlen; /* some compilers can't nest inline assembler.. */ tmp = ntohl(th->ackno) + i; th->ackno = htonl(tmp); tmp = ntohl(th->seqno) + i; th->seqno = htonl(tmp); } break; case SPECIAL_D: /* some compilers can't nest inline assembler.. */ tmp = ntohl(th->seqno) + ntohs(IPH_LEN(&cs->cs_ip)) - cs->cs_hlen; th->seqno = htonl(tmp); break; default: if (changes & NEW_U) { TCPH_SET_FLAG(th, TCP_URG); DECODEU(th->urgp); } else { TCPH_UNSET_FLAG(th, TCP_URG); } if (changes & NEW_W) { DECODES(th->wnd); } if (changes & NEW_A) { DECODEL(th->ackno); } if (changes & NEW_S) { DECODEL(th->seqno); } break; } if (changes & NEW_I) { DECODES(cs->cs_ip._id); } else { IPH_ID_SET(&cs->cs_ip, ntohs(IPH_ID(&cs->cs_ip)) + 1); IPH_ID_SET(&cs->cs_ip, htons(IPH_ID(&cs->cs_ip))); } /* * At this point, cp points to the first byte of data in the * packet. Fill in the IP total length and update the IP * header checksum. */ vjlen = (u_short)(cp - (u_char*)n0->payload); if (n0->len < vjlen) { /* * We must have dropped some characters (crc should detect * this but the old slip framing won't) */ PPPDEBUG(LOG_INFO, ("vj_uncompress_tcp: head buffer %d too short %d\n", n0->len, vjlen)); goto bad; }#if BYTE_ORDER == LITTLE_ENDIAN tmp = n0->tot_len - vjlen + cs->cs_hlen; IPH_LEN_SET(&cs->cs_ip, htons((u_short)tmp));#else IPH_LEN_SET(&cs->cs_ip, htons(n0->tot_len - vjlen + cs->cs_hlen));#endif /* recompute the ip header checksum */ bp = (u_short *) &cs->cs_ip; IPH_CHKSUM_SET(&cs->cs_ip, 0); for (tmp = 0; hlen > 0; hlen -= 2) { tmp += *bp++; } tmp = (tmp & 0xffff) + (tmp >> 16); tmp = (tmp & 0xffff) + (tmp >> 16); IPH_CHKSUM_SET(&cs->cs_ip, (u_short)(~tmp)); /* Remove the compressed header and prepend the uncompressed header. */ if(pbuf_header(n0, -((s16_t)(vjlen)))) { /* Can we cope with this failing? Just assert for now */ LWIP_ASSERT("pbuf_header failed\n", 0); goto bad; } if(LWIP_MEM_ALIGN(n0->payload) != n0->payload) { struct pbuf *np, *q; u8_t *bufptr; np = pbuf_alloc(PBUF_RAW, n0->len + cs->cs_hlen, PBUF_POOL); if(!np) { PPPDEBUG(LOG_WARNING, ("vj_uncompress_tcp: realign failed\n")); goto bad; } if(pbuf_header(np, -cs->cs_hlen)) { /* Can we cope with this failing? Just assert for now */ LWIP_ASSERT("pbuf_header failed\n", 0); goto bad; } bufptr = n0->payload; for(q = np; q != NULL; q = q->next) { MEMCPY(q->payload, bufptr, q->len); bufptr += q->len; } if(n0->next) { pbuf_chain(np, n0->next); pbuf_dechain(n0); } pbuf_free(n0); n0 = np; } if(pbuf_header(n0, cs->cs_hlen)) { struct pbuf *np; LWIP_ASSERT("vj_uncompress_tcp: cs->cs_hlen <= PBUF_POOL_BUFSIZE", cs->cs_hlen <= PBUF_POOL_BUFSIZE); np = pbuf_alloc(PBUF_RAW, cs->cs_hlen, PBUF_POOL); if(!np) { PPPDEBUG(LOG_WARNING, ("vj_uncompress_tcp: prepend failed\n")); goto bad; } pbuf_cat(np, n0); n0 = np; } LWIP_ASSERT("n0->len >= cs->cs_hlen", n0->len >= cs->cs_hlen); MEMCPY(n0->payload, &cs->cs_ip, cs->cs_hlen); *nb = n0; return vjlen;bad: comp->flags |= VJF_TOSS; INCR(vjs_errorin); return (-1);}#endif /* VJ_SUPPORT */#endif /* PPP_SUPPORT */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -