* so that the entire packet being decompressed doesn't have
* to be in contiguous memory (just the compressed header).
*
- * $Id: slcompress.c,v 1.1 1994/11/22 00:27:52 paulus Exp $
+ * $Id: slcompress.c,v 1.4 1997/03/04 03:45:18 paulus Exp $
*/
#include "../h/types.h"
#include "../net/netinet/ip.h"
#include "../net/netinet/tcp.h"
+#include "ppp_defs.h"
#include "slcompress.h"
#ifndef SL_NO_STATS
} \
}
-
-u_char
+u_int
sl_compress_tcp(m, ip, comp, compress_cid)
struct mbuf *m;
register struct ip *ip;
u_int type;
struct slcompress *comp;
{
- return sl_uncompress_tcp_part(bufp, len, len, type, comp);
-}
+ u_char *hdr, *cp;
+ int vjlen;
+ u_int hlen;
+
+ cp = bufp? *bufp: NULL;
+ vjlen = sl_uncompress_tcp_core(cp, len, len, type, comp, &hdr, &hlen);
+ if (vjlen < 0)
+ return (0); /* error */
+ if (vjlen == 0)
+ return (len); /* was uncompressed already */
+ cp += vjlen;
+ len -= vjlen;
+
+ /*
+ * 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).
+ */
+ if ((int)cp & 3) {
+ if (len > 0)
+ (void) ovbcopy(cp, (caddr_t)((int)cp &~ 3), len);
+ cp = (u_char *)((int)cp &~ 3);
+ }
+ cp -= hlen;
+ len += hlen;
+ BCOPY(hdr, cp, hlen);
+
+ *bufp = cp;
+ return (len);
+}
/*
* Uncompress a packet of total length total_len. The first buflen
- * bytes are at *bufp; this must include the entire (compressed or
- * uncompressed) TCP/IP header. In addition, there must be enough
- * clear space before *bufp to build a full-length TCP/IP header.
+ * bytes are at buf; this must include the entire (compressed or
+ * uncompressed) TCP/IP header. This procedure returns the length
+ * of the VJ header, with a pointer to the uncompressed IP header
+ * in *hdrp and its length in *hlenp.
*/
int
-sl_uncompress_tcp_part(bufp, buflen, total_len, type, comp)
- u_char **bufp;
+sl_uncompress_tcp_core(buf, buflen, total_len, type, comp, hdrp, hlenp)
+ u_char *buf;
int buflen, total_len;
u_int type;
struct slcompress *comp;
+ u_char **hdrp;
+ u_int *hlenp;
{
register u_char *cp;
register u_int hlen, changes;
register struct tcphdr *th;
register struct cstate *cs;
register struct ip *ip;
+ register u_short *bp;
+ register u_int vjlen;
switch (type) {
case TYPE_UNCOMPRESSED_TCP:
- ip = (struct ip *) *bufp;
+ ip = (struct ip *) buf;
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;
+ /*
+ * Calculate the size of the TCP/IP header and make sure that
+ * we don't overflow the space we have available for it.
+ */
+ hlen = ip->ip_hl << 2;
+ if (hlen + sizeof(struct tcphdr) > buflen)
+ goto bad;
+ hlen += ((struct tcphdr *)&((char *)ip)[hlen])->th_off << 2;
+ if (hlen > MAX_HDR || hlen > buflen)
+ goto bad;
BCOPY(ip, &cs->cs_ip, hlen);
- cs->cs_ip.ip_sum = 0;
cs->cs_hlen = hlen;
INCR(sls_uncompressedin)
- return (total_len);
+ *hdrp = (u_char *) &cs->cs_ip;
+ *hlenp = hlen;
+ return (0);
default:
goto bad;
}
/* We've got a compressed packet. */
INCR(sls_compressedin)
- cp = *bufp;
+ cp = buf;
changes = *cp++;
if (changes & NEW_C) {
/* Make sure the state index is in range, then grab the state.
* explicit state index, we have to toss the packet. */
if (comp->flags & SLF_TOSS) {
INCR(sls_tossed)
- return (0);
+ return (-1);
}
}
cs = &comp->rstate[comp->last_recv];
/*
* 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.
+ * packet. Fill in the IP total length and update the IP
+ * header checksum.
*/
- buflen -= (cp - *bufp);
- total_len -= (cp - *bufp);
+ vjlen = cp - buf;
+ buflen -= vjlen;
if (buflen < 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 (buflen > 0)
- (void) ovbcopy(cp, (caddr_t)((int)cp &~ 3), buflen);
- cp = (u_char *)((int)cp &~ 3);
- }
- cp -= cs->cs_hlen;
- total_len += cs->cs_hlen;
+ total_len += cs->cs_hlen - vjlen;
cs->cs_ip.ip_len = htons(total_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 (total_len);
+ bp = (u_short *) &cs->cs_ip;
+ cs->cs_ip.ip_sum = 0;
+ for (changes = 0; hlen > 0; hlen -= 2)
+ changes += *bp++;
+ changes = (changes & 0xffff) + (changes >> 16);
+ changes = (changes & 0xffff) + (changes >> 16);
+ cs->cs_ip.ip_sum = ~ changes;
+
+ *hdrp = (u_char *) &cs->cs_ip;
+ *hlenp = cs->cs_hlen;
+ return vjlen;
+
bad:
comp->flags |= SLF_TOSS;
INCR(sls_errorin)
- return (0);
+ return (-1);
}