X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/11b5360c2a20361f15b3777b000fbe61fff9d6d4..0fe7c40f5f0f6af89c8c7dc61cc7eebf454d0a84:/usr/src/sys/net/slcompress.c diff --git a/usr/src/sys/net/slcompress.c b/usr/src/sys/net/slcompress.c index 788bb6bb34..7e5e010a81 100644 --- a/usr/src/sys/net/slcompress.c +++ b/usr/src/sys/net/slcompress.c @@ -1,53 +1,45 @@ -/* slcompress.c 7.1 89/06/28 */ - -/* - * THIS CODE IS NOT FOR DISTRIBUTION! - * KEEP YOUR GRUBBY HANDS OFF UNLESS AUTHORIZED BY VAN JACOBSON TO COPY! - * ASK SAM, MIKE, OR BILL ABOUT IT. +/*- + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * %sccs.include.redist.c% + * + * @(#)slcompress.c 7.8 (Berkeley) %G% */ /* * Routines to compress and uncompess tcp packets (for transmission * over low speed serial lines. * - * Copyright (c) 1988, 1989 by Van Jacobson, Lawrence Berkeley Laboratory - * All rights reserved. + * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: + * - Initial distribution. + * + * static char rcsid[] = + * "$Header: slcompress.c,v 1.19 89/12/31 08:52:59 van Exp $"; */ -#ifndef lint -static char rcsid[] = "$Header: slcompress.c,v 1.7 89/03/19 18:10:19 van Locked $"; -#endif - -#include #include #include + #include #include #include #include -#include "slcompress.h" +#include -int sls_packets; -int sls_searches; -int sls_misses; -int sls_compressed; -int sls_ipin; -int sls_uncompressedin; -int sls_compressedin; +#ifndef SL_NO_STATS +#define INCR(counter) ++comp->counter; +#else +#define INCR(counter) +#endif #define BCMP(p1, p2, n) bcmp((char *)(p1), (char *)(p2), (int)(n)) #define BCOPY(p1, p2, n) bcopy((char *)(p1), (char *)(p2), (int)(n)) - #ifndef KERNEL -extern struct mbuf *m_get(); -#undef MGET -#define MGET(m, w, t) ((m) = m_get((w), (t))) +#define ovbcopy bcopy #endif -#if BSD>=198810 -#define m_off m_data -#endif void sl_compress_init(comp) @@ -112,12 +104,22 @@ sl_compress_init(comp) } \ } +#define DECODEU(f) { \ + if (*cp == 0) {\ + (f) = htons((cp[1] << 8) | cp[2]); \ + cp += 3; \ + } else { \ + (f) = htons((u_long)*cp++); \ + } \ +} + u_char -sl_compress_tcp(m, ip, comp) +sl_compress_tcp(m, ip, comp, compress_cid) struct mbuf *m; register struct ip *ip; struct slcompress *comp; + int compress_cid; { register struct cstate *cs = comp->last_cs->cs_next; register u_int hlen = ip->ip_hl; @@ -129,60 +131,61 @@ sl_compress_tcp(m, ip, comp) register u_char *cp = new_seq; /* - * Bail if this is an ip fragment or if we don't have - * a complete ip & tcp header in the first mbuf. Otherwise, - * check flags to see if this is a packet we might compress - * and, if so, try to locate the connection state. - * since slip links tend to be end nodes, check the tcp ports - * first since the inet addresses won't usually change. - * 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. + * 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). (We assume that the caller has already made sure the + * packet is IP proto TCP). */ - if ((ip->ip_off & 0x3fff) || m->m_len < 40) + if ((ip->ip_off & htons(0x3fff)) || m->m_len < 40) return (TYPE_IP); th = (struct tcphdr *)&((int *)ip)[hlen]; if ((th->th_flags & (TH_SYN|TH_FIN|TH_RST|TH_ACK)) != TH_ACK) return (TYPE_IP); - - ++sls_packets; - if (*(int *)th != ((int *)&cs->cs_ip)[cs->cs_ip.ip_hl] || - ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr || - ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr) { + /* + * 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(sls_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 || + *(int *)th != ((int *)&cs->cs_ip)[cs->cs_ip.ip_hl]) { /* * Wasn't the first -- search for it. * * States are kept in a circularly linked list with - * first_cs pointing to the head of the list. The + * 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 used. + * 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; - ++sls_searches; - if (*(int *)th == ((int *)&cs->cs_ip)[cs->cs_ip.ip_hl] - && ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr - && ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr) + INCR(sls_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 + && *(int *)th == ((int *)&cs->cs_ip)[cs->cs_ip.ip_hl]) goto found; - } while (cs != comp->last_cs); - ++sls_misses; + } 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. + * 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(sls_misses) comp->last_cs = lcs; hlen += th->th_off; hlen <<= 2; @@ -192,17 +195,25 @@ sl_compress_tcp(m, ip, comp) /* * Found it -- move to the front on the connection list. */ - if (comp->last_cs == cs) + if (cs == lastcs) comp->last_cs = lcs; else { lcs->cs_next = cs->cs_next; - cs->cs_next = comp->last_cs->cs_next; - comp->last_cs->cs_next = cs; + cs->cs_next = lastcs->cs_next; + lastcs->cs_next = cs; } } /* - * Make sure that only what we expect to change changed. + * 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; @@ -210,6 +221,7 @@ sl_compress_tcp(m, ip, comp) hlen <<= 2; 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 && @@ -232,7 +244,7 @@ sl_compress_tcp(m, ip, comp) /* 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. */ + * with it. */ goto uncompressed; if (deltaS = (u_short)(ntohs(th->th_win) - ntohs(oth->th_win))) { @@ -257,17 +269,19 @@ sl_compress_tcp(m, ip, comp) switch(changes) { case 0: - if (ip->ip_len != cs->cs_ip.ip_len && ntohs(ip->ip_len) != hlen) - break; /* - * Nothing changed and this packet looks like a duplicate - * of the last or contains no data -- this is probably a - * retransmitted ack or window probe. Send it - * uncompressed in case the other side missed the - * compressed version. - * - * (fall through) + * 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: @@ -320,24 +334,23 @@ sl_compress_tcp(m, ip, comp) */ deltaS = cp - new_seq; cp = (u_char *)ip; - if (comp->last_xmit != cs->cs_id) { + if (compress_cid == 0 || comp->last_xmit != cs->cs_id) { comp->last_xmit = cs->cs_id; hlen -= deltaS + 4; - cp += hlen; m->m_len -= hlen; m->m_off += hlen; + cp += hlen; *cp++ = changes | NEW_C; *cp++ = cs->cs_id; } else { hlen -= deltaS + 3; - cp += hlen; m->m_len -= hlen; m->m_off += hlen; + cp += hlen; *cp++ = changes; } + m->m_len -= hlen; + m->m_data += hlen; *cp++ = deltaA >> 8; *cp++ = deltaA; BCOPY(new_seq, cp, deltaS); - ++sls_compressed; - /* note: low order version bits used */ - ip = mtod(m, struct ip *); - ip->ip_v |= (TYPE_COMPRESSED_TCP>>4); + INCR(sls_compressed) return (TYPE_COMPRESSED_TCP); /* @@ -349,16 +362,15 @@ uncompressed: BCOPY(ip, &cs->cs_ip, hlen); ip->ip_p = cs->cs_id; comp->last_xmit = cs->cs_id; - ip->ip_v = (TYPE_UNCOMPRESSED_TCP>>4); return (TYPE_UNCOMPRESSED_TCP); } -int uncdeb ; -struct mbuf * -sl_uncompress_tcp(m, type, comp) - register struct mbuf *m; - u_char type; +int +sl_uncompress_tcp(bufp, len, type, comp) + u_char **bufp; + int len; + u_int type; struct slcompress *comp; { register u_char *cp; @@ -366,16 +378,13 @@ sl_uncompress_tcp(m, type, comp) register struct tcphdr *th; register struct cstate *cs; register struct ip *ip; - register struct mbuf *m0; switch (type) { case TYPE_UNCOMPRESSED_TCP: - ip = mtod(m, struct ip *); + ip = (struct ip *) *bufp; if (ip->ip_p >= MAX_STATES) goto bad; - ip->ip_v = 4; - cs = &comp->rstate[comp->last_recv = ip->ip_p]; comp->flags &=~ SLF_TOSS; ip->ip_p = IPPROTO_TCP; @@ -385,25 +394,18 @@ sl_uncompress_tcp(m, type, comp) BCOPY(ip, &cs->cs_ip, hlen); cs->cs_ip.ip_sum = 0; cs->cs_hlen = hlen; - ++sls_uncompressedin; - return (m); + INCR(sls_uncompressedin) + return (len); default: - if(type&TYPE_COMPRESSED_TCP) goto compre; - ++sls_ipin; - return (m); - - case TYPE_ERROR: - comp->flags |= SLF_TOSS; - return (m); + goto bad; case TYPE_COMPRESSED_TCP: -compre: break; } /* We've got a compressed packet. */ - ++sls_compressedin; - cp = mtod(m, u_char *); + INCR(sls_compressedin) + cp = *bufp; changes = *cp++; if (changes & NEW_C) { /* Make sure the state index is in range, then grab the state. @@ -417,8 +419,10 @@ compre: /* 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) - goto bad; + if (comp->flags & SLF_TOSS) { + INCR(sls_tossed) + return (0); + } } cs = &comp->rstate[comp->last_recv]; hlen = cs->cs_ip.ip_hl << 2; @@ -447,7 +451,7 @@ compre: default: if (changes & NEW_U) { th->th_flags |= TH_URG; - DECODES(th->th_urp) + DECODEU(th->th_urp) } else th->th_flags &=~ TH_URG; if (changes & NEW_W) @@ -465,36 +469,42 @@ compre: /* * At this point, cp points to the first byte of data in the - * packet (if any). Toss the compressed header from the - * original packet, allocatate a new mbuf for the uncompressed - * header (to make sure it's aligned correctly), then chain it - * in front of the original. Set up the ip length & ip checksum then - * return the rebuilt packet. + * 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. */ - changes = cp - mtod(m, u_char *); - m->m_off += changes; m->m_len -= changes; - changes = cs->cs_hlen; - for (m0 = m; m0; m0 = m0->m_next) - changes += m0->m_len; - cs->cs_ip.ip_len = htons(changes); - - /*MGET(m0, M_DONTWAIT, MT_DATA);*/ - MGETHDR(m0, M_DONTWAIT, MT_DATA); /* XXX! */ - if (! m0) + 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; - m0->m_next = m; - m0->m_pkthdr.rcvif = m->m_pkthdr.rcvif ; /* XXX! */ - m0->m_pkthdr.len = m->m_pkthdr.len; /* XXX! */ - m = m0; - m->m_len = cs->cs_hlen; - ip = mtod(m, struct ip *); - BCOPY(&cs->cs_ip, ip, cs->cs_hlen); - - ip->ip_sum = in_cksum(m, hlen); - return (m); - + if ((int)cp & 3) { + if (len > 0) + (void) ovbcopy(cp, (caddr_t)((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); + *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: - m_freem(m); - return ((struct mbuf *)0); + comp->flags |= SLF_TOSS; + INCR(sls_errorin) + return (0); }