1/*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1989, 1993, 1994
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 *	@(#)slcompress.c	8.2 (Berkeley) 4/16/94
32 * $FreeBSD$
33 */
34
35/*
36 * Routines to compress and uncompess tcp packets (for transmission
37 * over low speed serial lines.
38 *
39 * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
40 *	- Initial distribution.
41 *
42 */
43
44#include <sys/param.h>
45#include <sys/mbuf.h>
46#include <sys/systm.h>
47
48#include <netinet/in.h>
49#include <netinet/in_systm.h>
50#include <netinet/ip.h>
51#include <netinet/tcp.h>
52
53#include <net/slcompress.h>
54
55#ifndef SL_NO_STATS
56#define INCR(counter) ++comp->counter;
57#else
58#define INCR(counter)
59#endif
60
61#define BCMP(p1, p2, n) bcmp((void *)(p1), (void *)(p2), (int)(n))
62#define BCOPY(p1, p2, n) bcopy((void *)(p1), (void *)(p2), (int)(n))
63
64void
65sl_compress_init(struct slcompress *comp, int max_state)
66{
67	u_int i;
68	struct cstate *tstate = comp->tstate;
69
70	if (max_state == -1) {
71		max_state = MAX_STATES - 1;
72		bzero((char *)comp, sizeof(*comp));
73	} else {
74		/* Don't reset statistics */
75		bzero((char *)comp->tstate, sizeof(comp->tstate));
76		bzero((char *)comp->rstate, sizeof(comp->rstate));
77	}
78  	for (i = max_state; i > 0; --i) {
79		tstate[i].cs_id = i;
80		tstate[i].cs_next = &tstate[i - 1];
81	}
82	tstate[0].cs_next = &tstate[max_state];
83	tstate[0].cs_id = 0;
84	comp->last_cs = &tstate[0];
85	comp->last_recv = 255;
86	comp->last_xmit = 255;
87	comp->flags = SLF_TOSS;
88}
89
90
91/* ENCODE encodes a number that is known to be non-zero.  ENCODEZ
92 * checks for zero (since zero has to be encoded in the long, 3 byte
93 * form).
94 */
95#define ENCODE(n) { \
96	if ((u_int16_t)(n) >= 256) { \
97		*cp++ = 0; \
98		cp[1] = (n); \
99		cp[0] = (n) >> 8; \
100		cp += 2; \
101	} else { \
102		*cp++ = (n); \
103	} \
104}
105#define ENCODEZ(n) { \
106	if ((u_int16_t)(n) >= 256 || (u_int16_t)(n) == 0) { \
107		*cp++ = 0; \
108		cp[1] = (n); \
109		cp[0] = (n) >> 8; \
110		cp += 2; \
111	} else { \
112		*cp++ = (n); \
113	} \
114}
115
116#define DECODEL(f) { \
117	if (*cp == 0) {\
118		(f) = htonl(ntohl(f) + ((cp[1] << 8) | cp[2])); \
119		cp += 3; \
120	} else { \
121		(f) = htonl(ntohl(f) + (u_int32_t)*cp++); \
122	} \
123}
124
125#define DECODES(f) { \
126	if (*cp == 0) {\
127		(f) = htons(ntohs(f) + ((cp[1] << 8) | cp[2])); \
128		cp += 3; \
129	} else { \
130		(f) = htons(ntohs(f) + (u_int32_t)*cp++); \
131	} \
132}
133
134#define DECODEU(f) { \
135	if (*cp == 0) {\
136		(f) = htons((cp[1] << 8) | cp[2]); \
137		cp += 3; \
138	} else { \
139		(f) = htons((u_int32_t)*cp++); \
140	} \
141}
142
143/*
144 * Attempt to compress an outgoing TCP packet and return the type of
145 * the result.  The caller must have already verified that the protocol
146 * is TCP.  The first mbuf must contain the complete IP and TCP headers,
147 * and "ip" must be == mtod(m, struct ip *).  "comp" supplies the
148 * compression state, and "compress_cid" tells us whether it is OK
149 * to leave out the CID field when feasible.
150 *
151 * The caller is responsible for adjusting m->m_pkthdr.len upon return,
152 * if m is an M_PKTHDR mbuf.
153 */
154u_int
155sl_compress_tcp(struct mbuf *m, struct ip *ip, struct slcompress *comp,
156    int compress_cid)
157{
158	struct cstate *cs = comp->last_cs->cs_next;
159	u_int hlen = ip->ip_hl;
160	struct tcphdr *oth;
161	struct tcphdr *th;
162	u_int deltaS, deltaA;
163	u_int changes = 0;
164	u_char new_seq[16];
165	u_char *cp = new_seq;
166
167	/*
168	 * Bail if this is an IP fragment or if the TCP packet isn't
169	 * `compressible' (i.e., ACK isn't set or some other control bit is
170	 * set).  (We assume that the caller has already made sure the
171	 * packet is IP proto TCP).
172	 */
173	if ((ip->ip_off & htons(0x3fff)) || m->m_len < 40)
174		return (TYPE_IP);
175
176	th = (struct tcphdr *)&((int32_t *)ip)[hlen];
177	if ((th->th_flags & (TH_SYN|TH_FIN|TH_RST|TH_ACK)) != TH_ACK)
178		return (TYPE_IP);
179	/*
180	 * Packet is compressible -- we're going to send either a
181	 * COMPRESSED_TCP or UNCOMPRESSED_TCP packet.  Either way we need
182	 * to locate (or create) the connection state.  Special case the
183	 * most recently used connection since it's most likely to be used
184	 * again & we don't have to do any reordering if it's used.
185	 */
186	INCR(sls_packets)
187	if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr ||
188	    ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr ||
189	    *(int32_t *)th != ((int32_t *)&cs->cs_ip)[cs->cs_ip.ip_hl]) {
190		/*
191		 * Wasn't the first -- search for it.
192		 *
193		 * States are kept in a circularly linked list with
194		 * last_cs pointing to the end of the list.  The
195		 * list is kept in lru order by moving a state to the
196		 * head of the list whenever it is referenced.  Since
197		 * the list is short and, empirically, the connection
198		 * we want is almost always near the front, we locate
199		 * states via linear search.  If we don't find a state
200		 * for the datagram, the oldest state is (re-)used.
201		 */
202		struct cstate *lcs;
203		struct cstate *lastcs = comp->last_cs;
204
205		do {
206			lcs = cs; cs = cs->cs_next;
207			INCR(sls_searches)
208			if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr
209			    && ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr
210			    && *(int32_t *)th ==
211			    ((int32_t *)&cs->cs_ip)[cs->cs_ip.ip_hl])
212				goto found;
213		} while (cs != lastcs);
214
215		/*
216		 * Didn't find it -- re-use oldest cstate.  Send an
217		 * uncompressed packet that tells the other side what
218		 * connection number we're using for this conversation.
219		 * Note that since the state list is circular, the oldest
220		 * state points to the newest and we only need to set
221		 * last_cs to update the lru linkage.
222		 */
223		INCR(sls_misses)
224		comp->last_cs = lcs;
225		hlen += th->th_off;
226		hlen <<= 2;
227		if (hlen > m->m_len)
228		    return TYPE_IP;
229		goto uncompressed;
230
231	found:
232		/*
233		 * Found it -- move to the front on the connection list.
234		 */
235		if (cs == lastcs)
236			comp->last_cs = lcs;
237		else {
238			lcs->cs_next = cs->cs_next;
239			cs->cs_next = lastcs->cs_next;
240			lastcs->cs_next = cs;
241		}
242	}
243
244	/*
245	 * Make sure that only what we expect to change changed. The first
246	 * line of the `if' checks the IP protocol version, header length &
247	 * type of service.  The 2nd line checks the "Don't fragment" bit.
248	 * The 3rd line checks the time-to-live and protocol (the protocol
249	 * check is unnecessary but costless).  The 4th line checks the TCP
250	 * header length.  The 5th line checks IP options, if any.  The 6th
251	 * line checks TCP options, if any.  If any of these things are
252	 * different between the previous & current datagram, we send the
253	 * current datagram `uncompressed'.
254	 */
255	oth = (struct tcphdr *)&((int32_t *)&cs->cs_ip)[hlen];
256	deltaS = hlen;
257	hlen += th->th_off;
258	hlen <<= 2;
259	if (hlen > m->m_len)
260	    return TYPE_IP;
261
262	if (((u_int16_t *)ip)[0] != ((u_int16_t *)&cs->cs_ip)[0] ||
263	    ((u_int16_t *)ip)[3] != ((u_int16_t *)&cs->cs_ip)[3] ||
264	    ((u_int16_t *)ip)[4] != ((u_int16_t *)&cs->cs_ip)[4] ||
265	    th->th_off != oth->th_off ||
266	    (deltaS > 5 &&
267	     BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) ||
268	    (th->th_off > 5 &&
269	     BCMP(th + 1, oth + 1, (th->th_off - 5) << 2)))
270		goto uncompressed;
271
272	/*
273	 * Figure out which of the changing fields changed.  The
274	 * receiver expects changes in the order: urgent, window,
275	 * ack, seq (the order minimizes the number of temporaries
276	 * needed in this section of code).
277	 */
278	if (th->th_flags & TH_URG) {
279		deltaS = ntohs(th->th_urp);
280		ENCODEZ(deltaS);
281		changes |= NEW_U;
282	} else if (th->th_urp != oth->th_urp)
283		/* argh! URG not set but urp changed -- a sensible
284		 * implementation should never do this but RFC793
285		 * doesn't prohibit the change so we have to deal
286		 * with it. */
287		 goto uncompressed;
288
289	deltaS = (u_int16_t)(ntohs(th->th_win) - ntohs(oth->th_win));
290	if (deltaS) {
291		ENCODE(deltaS);
292		changes |= NEW_W;
293	}
294
295	deltaA = ntohl(th->th_ack) - ntohl(oth->th_ack);
296	if (deltaA) {
297		if (deltaA > 0xffff)
298			goto uncompressed;
299		ENCODE(deltaA);
300		changes |= NEW_A;
301	}
302
303	deltaS = ntohl(th->th_seq) - ntohl(oth->th_seq);
304	if (deltaS) {
305		if (deltaS > 0xffff)
306			goto uncompressed;
307		ENCODE(deltaS);
308		changes |= NEW_S;
309	}
310
311	switch(changes) {
312
313	case 0:
314		/*
315		 * Nothing changed. If this packet contains data and the
316		 * last one didn't, this is probably a data packet following
317		 * an ack (normal on an interactive connection) and we send
318		 * it compressed.  Otherwise it's probably a retransmit,
319		 * retransmitted ack or window probe.  Send it uncompressed
320		 * in case the other side missed the compressed version.
321		 */
322		if (ip->ip_len != cs->cs_ip.ip_len &&
323		    ntohs(cs->cs_ip.ip_len) == hlen)
324			break;
325
326		/* FALLTHROUGH */
327
328	case SPECIAL_I:
329	case SPECIAL_D:
330		/*
331		 * actual changes match one of our special case encodings --
332		 * send packet uncompressed.
333		 */
334		goto uncompressed;
335
336	case NEW_S|NEW_A:
337		if (deltaS == deltaA &&
338		    deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {
339			/* special case for echoed terminal traffic */
340			changes = SPECIAL_I;
341			cp = new_seq;
342		}
343		break;
344
345	case NEW_S:
346		if (deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {
347			/* special case for data xfer */
348			changes = SPECIAL_D;
349			cp = new_seq;
350		}
351		break;
352	}
353
354	deltaS = ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id);
355	if (deltaS != 1) {
356		ENCODEZ(deltaS);
357		changes |= NEW_I;
358	}
359	if (th->th_flags & TH_PUSH)
360		changes |= TCP_PUSH_BIT;
361	/*
362	 * Grab the cksum before we overwrite it below.  Then update our
363	 * state with this packet's header.
364	 */
365	deltaA = ntohs(th->th_sum);
366	BCOPY(ip, &cs->cs_ip, hlen);
367
368	/*
369	 * We want to use the original packet as our compressed packet.
370	 * (cp - new_seq) is the number of bytes we need for compressed
371	 * sequence numbers.  In addition we need one byte for the change
372	 * mask, one for the connection id and two for the tcp checksum.
373	 * So, (cp - new_seq) + 4 bytes of header are needed.  hlen is how
374	 * many bytes of the original packet to toss so subtract the two to
375	 * get the new packet size.
376	 */
377	deltaS = cp - new_seq;
378	cp = (u_char *)ip;
379	if (compress_cid == 0 || comp->last_xmit != cs->cs_id) {
380		comp->last_xmit = cs->cs_id;
381		hlen -= deltaS + 4;
382		cp += hlen;
383		*cp++ = changes | NEW_C;
384		*cp++ = cs->cs_id;
385	} else {
386		hlen -= deltaS + 3;
387		cp += hlen;
388		*cp++ = changes;
389	}
390	m->m_len -= hlen;
391	m->m_data += hlen;
392	*cp++ = deltaA >> 8;
393	*cp++ = deltaA;
394	BCOPY(new_seq, cp, deltaS);
395	INCR(sls_compressed)
396	return (TYPE_COMPRESSED_TCP);
397
398	/*
399	 * Update connection state cs & send uncompressed packet ('uncompressed'
400	 * means a regular ip/tcp packet but with the 'conversation id' we hope
401	 * to use on future compressed packets in the protocol field).
402	 */
403uncompressed:
404	BCOPY(ip, &cs->cs_ip, hlen);
405	ip->ip_p = cs->cs_id;
406	comp->last_xmit = cs->cs_id;
407	return (TYPE_UNCOMPRESSED_TCP);
408}
409
410
411int
412sl_uncompress_tcp(u_char **bufp, int len, u_int type, struct slcompress *comp)
413{
414	u_char *hdr, *cp;
415	int hlen, vjlen;
416
417	cp = bufp? *bufp: NULL;
418	vjlen = sl_uncompress_tcp_core(cp, len, len, type, comp, &hdr, &hlen);
419	if (vjlen < 0)
420		return (0);	/* error */
421	if (vjlen == 0)
422		return (len);	/* was uncompressed already */
423
424	cp += vjlen;
425	len -= vjlen;
426
427	/*
428	 * At this point, cp points to the first byte of data in the
429	 * packet.  If we're not aligned on a 4-byte boundary, copy the
430	 * data down so the ip & tcp headers will be aligned.  Then back up
431	 * cp by the tcp/ip header length to make room for the reconstructed
432	 * header (we assume the packet we were handed has enough space to
433	 * prepend 128 bytes of header).
434	 */
435	if ((intptr_t)cp & 3) {
436		if (len > 0)
437			BCOPY(cp, ((intptr_t)cp &~ 3), len);
438		cp = (u_char *)((intptr_t)cp &~ 3);
439	}
440	cp -= hlen;
441	len += hlen;
442	BCOPY(hdr, cp, hlen);
443
444	*bufp = cp;
445	return (len);
446}
447
448/*
449 * Uncompress a packet of total length total_len.  The first buflen
450 * bytes are at buf; this must include the entire (compressed or
451 * uncompressed) TCP/IP header.  This procedure returns the length
452 * of the VJ header, with a pointer to the uncompressed IP header
453 * in *hdrp and its length in *hlenp.
454 */
455int
456sl_uncompress_tcp_core(u_char *buf, int buflen, int total_len, u_int type,
457    struct slcompress *comp, u_char **hdrp, u_int *hlenp)
458{
459	u_char *cp;
460	u_int hlen, changes;
461	struct tcphdr *th;
462	struct cstate *cs;
463	struct ip *ip;
464	u_int16_t *bp;
465	u_int vjlen;
466
467	switch (type) {
468
469	case TYPE_UNCOMPRESSED_TCP:
470		ip = (struct ip *) buf;
471		if (ip->ip_p >= MAX_STATES)
472			goto bad;
473		cs = &comp->rstate[comp->last_recv = ip->ip_p];
474		comp->flags &=~ SLF_TOSS;
475		ip->ip_p = IPPROTO_TCP;
476		/*
477		 * Calculate the size of the TCP/IP header and make sure that
478		 * we don't overflow the space we have available for it.
479		 */
480		hlen = ip->ip_hl << 2;
481		if (hlen + sizeof(struct tcphdr) > buflen)
482			goto bad;
483		hlen += ((struct tcphdr *)&((char *)ip)[hlen])->th_off << 2;
484		if (hlen > MAX_HDR || hlen > buflen)
485			goto bad;
486		BCOPY(ip, &cs->cs_ip, hlen);
487		cs->cs_hlen = hlen;
488		INCR(sls_uncompressedin)
489		*hdrp = (u_char *) &cs->cs_ip;
490		*hlenp = hlen;
491		return (0);
492
493	default:
494		goto bad;
495
496	case TYPE_COMPRESSED_TCP:
497		break;
498	}
499	/* We've got a compressed packet. */
500	INCR(sls_compressedin)
501	cp = buf;
502	changes = *cp++;
503	if (changes & NEW_C) {
504		/* Make sure the state index is in range, then grab the state.
505		 * If we have a good state index, clear the 'discard' flag. */
506		if (*cp >= MAX_STATES)
507			goto bad;
508
509		comp->flags &=~ SLF_TOSS;
510		comp->last_recv = *cp++;
511	} else {
512		/* this packet has an implicit state index.  If we've
513		 * had a line error since the last time we got an
514		 * explicit state index, we have to toss the packet. */
515		if (comp->flags & SLF_TOSS) {
516			INCR(sls_tossed)
517			return (-1);
518		}
519	}
520	cs = &comp->rstate[comp->last_recv];
521	hlen = cs->cs_ip.ip_hl << 2;
522	th = (struct tcphdr *)&((u_char *)&cs->cs_ip)[hlen];
523	th->th_sum = htons((*cp << 8) | cp[1]);
524	cp += 2;
525	if (changes & TCP_PUSH_BIT)
526		th->th_flags |= TH_PUSH;
527	else
528		th->th_flags &=~ TH_PUSH;
529
530	switch (changes & SPECIALS_MASK) {
531	case SPECIAL_I:
532		{
533		u_int i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen;
534		th->th_ack = htonl(ntohl(th->th_ack) + i);
535		th->th_seq = htonl(ntohl(th->th_seq) + i);
536		}
537		break;
538
539	case SPECIAL_D:
540		th->th_seq = htonl(ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len)
541				   - cs->cs_hlen);
542		break;
543
544	default:
545		if (changes & NEW_U) {
546			th->th_flags |= TH_URG;
547			DECODEU(th->th_urp)
548		} else
549			th->th_flags &=~ TH_URG;
550		if (changes & NEW_W)
551			DECODES(th->th_win)
552		if (changes & NEW_A)
553			DECODEL(th->th_ack)
554		if (changes & NEW_S)
555			DECODEL(th->th_seq)
556		break;
557	}
558	if (changes & NEW_I) {
559		DECODES(cs->cs_ip.ip_id)
560	} else
561		cs->cs_ip.ip_id = htons(ntohs(cs->cs_ip.ip_id) + 1);
562
563	/*
564	 * At this point, cp points to the first byte of data in the
565	 * packet.  Fill in the IP total length and update the IP
566	 * header checksum.
567	 */
568	vjlen = cp - buf;
569	buflen -= vjlen;
570	if (buflen < 0)
571		/* we must have dropped some characters (crc should detect
572		 * this but the old slip framing won't) */
573		goto bad;
574
575	total_len += cs->cs_hlen - vjlen;
576	cs->cs_ip.ip_len = htons(total_len);
577
578	/* recompute the ip header checksum */
579	bp = (u_int16_t *) &cs->cs_ip;
580	cs->cs_ip.ip_sum = 0;
581		for (changes = 0; hlen > 0; hlen -= 2)
582			changes += *bp++;
583		changes = (changes & 0xffff) + (changes >> 16);
584		changes = (changes & 0xffff) + (changes >> 16);
585	cs->cs_ip.ip_sum = ~ changes;
586
587	*hdrp = (u_char *) &cs->cs_ip;
588	*hlenp = cs->cs_hlen;
589	return vjlen;
590
591bad:
592	comp->flags |= SLF_TOSS;
593	INCR(sls_errorin)
594	return (-1);
595}
596