X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=palacios%2Fsrc%2Flwip%2Fnetif%2Fppp%2Fvj.c;fp=palacios%2Fsrc%2Flwip%2Fnetif%2Fppp%2Fvj.c;h=0000000000000000000000000000000000000000;hb=0aae9daea0f73b79ab367a295d4640af39d97e8f;hp=814ea72c5e978273b0f9b1302b7a54527d6552a9;hpb=af3905e8868c6428c147e402eeb8dad3c4b434e6;p=palacios-OLD.git diff --git a/palacios/src/lwip/netif/ppp/vj.c b/palacios/src/lwip/netif/ppp/vj.c deleted file mode 100644 index 814ea72..0000000 --- a/palacios/src/lwip/netif/ppp/vj.c +++ /dev/null @@ -1,660 +0,0 @@ -/* - * Routines to compress and uncompess tcp packets (for transmission - * over low speed serial lines. - * - * Copyright (c) 1989 Regents of the University of California. - * All rights reserved. - * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the University of California, Berkeley. The name of the - * University may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: - * Initial distribution. - * - * Modified June 1993 by Paul Mackerras, paulus@cs.anu.edu.au, - * so that the entire packet being decompressed doesn't have - * to be in contiguous memory (just the compressed header). - * - * Modified March 1998 by Guy Lancaster, glanca@gesn.com, - * for a 16 bit processor. - */ - -#include "lwip/opt.h" - -#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ - -#include "ppp.h" -#include "pppdebug.h" - -#include "vj.h" - -#include - -#if VJ_SUPPORT - -#if LINK_STATS -#define INCR(counter) ++comp->stats.counter -#else -#define INCR(counter) -#endif - -#if defined(NO_CHAR_BITFIELDS) -#define getip_hl(base) ((base).ip_hl_v&0xf) -#define getth_off(base) (((base).th_x2_off&0xf0)>>4) -#else -#define getip_hl(base) ((base).ip_hl) -#define getth_off(base) ((base).th_off) -#endif - -void -vj_compress_init(struct vjcompress *comp) -{ - register u_int i; - register struct cstate *tstate = comp->tstate; - -#if MAX_SLOTS == 0 - memset((char *)comp, 0, sizeof(*comp)); -#endif - comp->maxSlotIndex = MAX_SLOTS - 1; - comp->compressSlot = 0; /* Disable slot ID compression by default. */ - for (i = MAX_SLOTS - 1; i > 0; --i) { - tstate[i].cs_id = i; - tstate[i].cs_next = &tstate[i - 1]; - } - tstate[0].cs_next = &tstate[MAX_SLOTS - 1]; - tstate[0].cs_id = 0; - comp->last_cs = &tstate[0]; - comp->last_recv = 255; - comp->last_xmit = 255; - comp->flags = VJF_TOSS; -} - - -/* ENCODE encodes a number that is known to be non-zero. ENCODEZ - * checks for zero (since zero has to be encoded in the long, 3 byte - * form). - */ -#define ENCODE(n) { \ - if ((u_short)(n) >= 256) { \ - *cp++ = 0; \ - cp[1] = (n); \ - cp[0] = (n) >> 8; \ - cp += 2; \ - } else { \ - *cp++ = (n); \ - } \ -} -#define ENCODEZ(n) { \ - if ((u_short)(n) >= 256 || (u_short)(n) == 0) { \ - *cp++ = 0; \ - cp[1] = (n); \ - cp[0] = (n) >> 8; \ - cp += 2; \ - } else { \ - *cp++ = (n); \ - } \ -} - -#define DECODEL(f) { \ - if (*cp == 0) {\ - u32_t tmp = ntohl(f) + ((cp[1] << 8) | cp[2]); \ - (f) = htonl(tmp); \ - cp += 3; \ - } else { \ - u32_t tmp = ntohl(f) + (u32_t)*cp++; \ - (f) = htonl(tmp); \ - } \ -} - -#define DECODES(f) { \ - if (*cp == 0) {\ - u_short tmp = ntohs(f) + (((u_short)cp[1] << 8) | cp[2]); \ - (f) = htons(tmp); \ - cp += 3; \ - } else { \ - u_short tmp = ntohs(f) + (u_short)*cp++; \ - (f) = htons(tmp); \ - } \ -} - -#define DECODEU(f) { \ - if (*cp == 0) {\ - (f) = htons(((u_short)cp[1] << 8) | cp[2]); \ - cp += 3; \ - } else { \ - (f) = htons((u_short)*cp++); \ - } \ -} - -/* - * vj_compress_tcp - Attempt to do Van Jacobsen header compression on a - * packet. This assumes that nb and comp are not null and that the first - * buffer of the chain contains a valid IP header. - * Return the VJ type code indicating whether or not the packet was - * compressed. - */ -u_int -vj_compress_tcp(struct vjcompress *comp, struct pbuf *pb) -{ - register struct ip *ip = (struct ip *)pb->payload; - register struct cstate *cs = comp->last_cs->cs_next; - register u_short hlen = getip_hl(*ip); - register struct tcphdr *oth; - register struct tcphdr *th; - register u_short deltaS, deltaA; - register u_long deltaL; - register u_int changes = 0; - u_char new_seq[16]; - register u_char *cp = new_seq; - - /* - * Check that the packet is IP proto TCP. - */ - if (ip->ip_p != IPPROTO_TCP) { - return (TYPE_IP); - } - - /* - * Bail if this is an IP fragment or if the TCP packet isn't - * `compressible' (i.e., ACK isn't set or some other control bit is - * set). - */ - if ((ip->ip_off & htons(0x3fff)) || pb->tot_len < 40) { - return (TYPE_IP); - } - th = (struct tcphdr *)&((long *)ip)[hlen]; - if ((th->th_flags & (TCP_SYN|TCP_FIN|TCP_RST|TCP_ACK)) != TCP_ACK) { - return (TYPE_IP); - } - /* - * Packet is compressible -- we're going to send either a - * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way we need - * to locate (or create) the connection state. Special case the - * most recently used connection since it's most likely to be used - * again & we don't have to do any reordering if it's used. - */ - INCR(vjs_packets); - if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr - || ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr - || *(long *)th != ((long *)&cs->cs_ip)[getip_hl(cs->cs_ip)]) { - /* - * Wasn't the first -- search for it. - * - * States are kept in a circularly linked list with - * last_cs pointing to the end of the list. The - * list is kept in lru order by moving a state to the - * head of the list whenever it is referenced. Since - * the list is short and, empirically, the connection - * we want is almost always near the front, we locate - * states via linear search. If we don't find a state - * for the datagram, the oldest state is (re-)used. - */ - register struct cstate *lcs; - register struct cstate *lastcs = comp->last_cs; - - do { - lcs = cs; cs = cs->cs_next; - INCR(vjs_searches); - if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr - && ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr - && *(long *)th == ((long *)&cs->cs_ip)[getip_hl(cs->cs_ip)]) { - goto found; - } - } while (cs != lastcs); - - /* - * Didn't find it -- re-use oldest cstate. Send an - * uncompressed packet that tells the other side what - * connection number we're using for this conversation. - * Note that since the state list is circular, the oldest - * state points to the newest and we only need to set - * last_cs to update the lru linkage. - */ - INCR(vjs_misses); - comp->last_cs = lcs; - hlen += getth_off(*th); - hlen <<= 2; - /* Check that the IP/TCP headers are contained in the first buffer. */ - if (hlen > pb->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; - } - } - - oth = (struct tcphdr *)&((long *)&cs->cs_ip)[hlen]; - deltaS = hlen; - hlen += getth_off(*th); - hlen <<= 2; - /* Check that the IP/TCP headers are contained in the first buffer. */ - if (hlen > pb->len) { - PPPDEBUG((LOG_INFO, "vj_compress_tcp: header len %d spans buffers\n", hlen)); - return (TYPE_IP); - } - - /* - * 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'. - */ - 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] - || getth_off(*th) != getth_off(*oth) - || (deltaS > 5 && BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) - || (getth_off(*th) > 5 && BCMP(th + 1, oth + 1, (getth_off(*th) - 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 & TCP_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))) != 0) { - ENCODE(deltaS); - changes |= NEW_W; - } - - if ((deltaL = ntohl(th->th_ack) - ntohl(oth->th_ack)) != 0) { - if (deltaL > 0xffff) { - goto uncompressed; - } - deltaA = (u_short)deltaL; - ENCODE(deltaA); - changes |= NEW_A; - } - - if ((deltaL = ntohl(th->th_seq) - ntohl(oth->th_seq)) != 0) { - if (deltaL > 0xffff) { - goto uncompressed; - } - deltaS = (u_short)deltaL; - 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 = (u_short)(ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id)); - if (deltaS != 1) { - ENCODEZ(deltaS); - changes |= NEW_I; - } - if (th->th_flags & 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->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 = (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++ = 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++ = changes; - } - *cp++ = deltaA >> 8; - *cp++ = 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); - ip->ip_p = cs->cs_id; - comp->last_xmit = cs->cs_id; - return (TYPE_UNCOMPRESSED_TCP); -} - -/* - * Called when we may have missed a packet. - */ -void -vj_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. - */ -int -vj_uncompress_uncomp(struct pbuf *nb, struct vjcompress *comp) -{ - register u_int hlen; - register struct cstate *cs; - register struct ip *ip; - - ip = (struct ip *)nb->payload; - hlen = getip_hl(*ip) << 2; - if (ip->ip_p >= MAX_SLOTS - || hlen + sizeof(struct tcphdr) > nb->len - || (hlen += getth_off(*((struct tcphdr *)&((char *)ip)[hlen])) << 2) - > nb->len - || hlen > MAX_HDR) { - PPPDEBUG((LOG_INFO, "vj_uncompress_uncomp: bad cid=%d, hlen=%d buflen=%d\n", - ip->ip_p, hlen, nb->len)); - comp->flags |= VJF_TOSS; - INCR(vjs_errorin); - return -1; - } - cs = &comp->rstate[comp->last_recv = ip->ip_p]; - comp->flags &=~ VJF_TOSS; - ip->ip_p = IPPROTO_TCP; - BCOPY(ip, &cs->cs_ip, hlen); - cs->cs_hlen = 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. - */ -int -vj_uncompress_tcp(struct pbuf **nb, struct vjcompress *comp) -{ - u_char *cp; - struct tcphdr *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 = getip_hl(cs->cs_ip) << 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 |= TCP_PSH; - } else { - th->th_flags &=~ TCP_PSH; - } - - switch (changes & SPECIALS_MASK) { - case SPECIAL_I: - { - register u32_t i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen; - /* some compilers can't nest inline assembler.. */ - tmp = ntohl(th->th_ack) + i; - th->th_ack = htonl(tmp); - tmp = ntohl(th->th_seq) + i; - th->th_seq = htonl(tmp); - } - break; - - case SPECIAL_D: - /* some compilers can't nest inline assembler.. */ - tmp = ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len) - cs->cs_hlen; - th->th_seq = htonl(tmp); - break; - - default: - if (changes & NEW_U) { - th->th_flags |= TCP_URG; - DECODEU(th->th_urp); - } else { - th->th_flags &=~ TCP_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 = ntohs(cs->cs_ip.ip_id) + 1; - cs->cs_ip.ip_id = htons(cs->cs_ip.ip_id); - } - - /* - * 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; - cs->cs_ip.ip_len = htons(tmp); -#else - cs->cs_ip.ip_len = htons(n0->tot_len - vjlen + cs->cs_hlen); -#endif - - /* recompute the ip header checksum */ - bp = (u_short *) &cs->cs_ip; - cs->cs_ip.ip_sum = 0; - for (tmp = 0; hlen > 0; hlen -= 2) { - tmp += *bp++; - } - tmp = (tmp & 0xffff) + (tmp >> 16); - tmp = (tmp & 0xffff) + (tmp >> 16); - cs->cs_ip.ip_sum = (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 */