11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Routines to compress and uncompress tcp packets (for transmission
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * over low speed serial lines).
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (c) 1989 Regents of the University of California.
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * All rights reserved.
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Redistribution and use in source and binary forms are permitted
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * provided that the above copyright notice and this paragraph are
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * duplicated in all such forms and that any documentation,
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * advertising materials, and other materials related to such
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * distribution and use acknowledge that the software was developed
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * by the University of California, Berkeley.  The name of the
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * University may not be used to endorse or promote products derived
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * from this software without specific prior written permission.
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- Initial distribution.
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * modified for KA9Q Internet Software Package by
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Katie Stevens (dkstevens@ucdavis.edu)
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * University of California, Davis
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Computing Services
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- 01-31-90	initial adaptation (from 1.19)
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	PPP.05	02-15-90 [ks]
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	PPP.08	05-02-90 [ks]	use PPP protocol field to signal compression
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	PPP.15	09-90	 [ks]	improve mbuf handling
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	PPP.16	11-02	 [karn]	substantially rewritten to use NOS facilities
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- Feb 1991	Bill_Simpson@um.cc.umich.edu
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *			variable number of conversation slots
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *			allow zero or one slots
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *			separate routines
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *			status display
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- Jul 1994	Dmitry Gorodchanin
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *			Fixes for memory leaks.
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      - Oct 1994      Dmitry Gorodchanin
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                      Modularization.
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- Jan 1995	Bjorn Ekwall
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *			Use ip_fast_csum from ip.h
456aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik *	- July 1995	Christos A. Polyzols
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *			Spotted bug in tcp option checking
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	This module is a difficult issue. It's clearly inet code but it's also clearly
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	driver code belonging close to PPP and SLIP
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
545a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/slhc_vj.h>
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_INET
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Entire module is for IP only */
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h>
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/socket.h>
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sockios.h>
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/termios.h>
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/in.h>
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fcntl.h>
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/inet.h>
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h>
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/ip.h>
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/protocol.h>
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/icmp.h>
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/tcp.h>
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h>
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/sock.h>
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/timer.h>
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/checksum.h>
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/unaligned.h>
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned char *encode(unsigned char *cp, unsigned short n);
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic long decode(unsigned char **cpp);
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned char * put16(unsigned char *cp, unsigned short x);
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned short pull16(unsigned char **cpp);
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Initialize compression data structure
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	slots must be in range 0 to 255 (zero meaning no compression)
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct slcompress *
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsslhc_init(int rslots, int tslots)
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register short i;
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register struct cstate *ts;
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct slcompress *comp;
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9779690602adc5b52ce224df6ac67bde0074b2aedeRalf Baechle	comp = kzalloc(sizeof(struct slcompress), GFP_KERNEL);
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (! comp)
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out_fail;
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ( rslots > 0  &&  rslots < 256 ) {
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size_t rsize = rslots * sizeof(struct cstate);
10379690602adc5b52ce224df6ac67bde0074b2aedeRalf Baechle		comp->rstate = kzalloc(rsize, GFP_KERNEL);
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (! comp->rstate)
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out_free;
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		comp->rslot_limit = rslots - 1;
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ( tslots > 0  &&  tslots < 256 ) {
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size_t tsize = tslots * sizeof(struct cstate);
11179690602adc5b52ce224df6ac67bde0074b2aedeRalf Baechle		comp->tstate = kzalloc(tsize, GFP_KERNEL);
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (! comp->tstate)
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out_free2;
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		comp->tslot_limit = tslots - 1;
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	comp->xmit_oldest = 0;
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	comp->xmit_current = 255;
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	comp->recv_current = 255;
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * don't accept any packets with implicit index until we get
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * one with an explicit index.  Otherwise the uncompress code
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * will try to use connection 255, which is almost certainly
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * out of range
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	comp->flags |= SLF_TOSS;
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ( tslots > 0 ) {
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ts = comp->tstate;
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for(i = comp->tslot_limit; i > 0; --i){
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ts[i].cs_this = i;
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ts[i].next = &(ts[i - 1]);
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ts[0].next = &(ts[comp->tslot_limit]);
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ts[0].cs_this = 0;
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return comp;
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_free2:
14079690602adc5b52ce224df6ac67bde0074b2aedeRalf Baechle	kfree(comp->rstate);
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_free:
14279690602adc5b52ce224df6ac67bde0074b2aedeRalf Baechle	kfree(comp);
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_fail:
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Free a compression data structure */
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsslhc_free(struct slcompress *comp)
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ( comp == NULLSLCOMPR )
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ( comp->tstate != NULLSLSTATE )
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree( comp->tstate );
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ( comp->rstate != NULLSLSTATE )
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree( comp->rstate );
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree( comp );
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Put a short in host order into a char array in network order */
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline unsigned char *
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsput16(unsigned char *cp, unsigned short x)
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*cp++ = x >> 8;
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*cp++ = x;
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return cp;
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Encode a number */
1773c582b30bc2592081e9b23e253ca098fa7d57dc2Stephen Hemmingerstatic unsigned char *
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsencode(unsigned char *cp, unsigned short n)
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(n >= 256 || n == 0){
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*cp++ = 0;
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cp = put16(cp,n);
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*cp++ = n;
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return cp;
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Pull a 16-bit integer in host order from buffer in network byte order */
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned short
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldspull16(unsigned char **cpp)
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	short rval;
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rval = *(*cpp)++;
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rval <<= 8;
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rval |= *(*cpp)++;
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rval;
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Decode a number */
2023c582b30bc2592081e9b23e253ca098fa7d57dc2Stephen Hemmingerstatic long
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdecode(unsigned char **cpp)
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register int x;
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	x = *(*cpp)++;
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(x == 0){
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return pull16(cpp) & 0xffff;	/* pull16 returns -1 on error */
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return x & 0xff;		/* -1 if PULLCHAR returned error */
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * icp and isize are the original packet.
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ocp is a place to put a copy if necessary.
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cpp is initially a pointer to icp.  If the copy is used,
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    change it to ocp.
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsslhc_compress(struct slcompress *comp, unsigned char *icp, int isize,
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *ocp, unsigned char **cpp, int compress_cid)
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register struct cstate *ocs = &(comp->tstate[comp->xmit_oldest]);
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register struct cstate *lcs = ocs;
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register struct cstate *cs = lcs->next;
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register unsigned long deltaS, deltaA;
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register short changes = 0;
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int hlen;
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char new_seq[16];
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register unsigned char *cp = new_seq;
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct iphdr *ip;
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tcphdr *th, *oth;
2367cd61888d2ab9fa7e08205b18a24885e523df048Al Viro	__sum16 csum;
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *	Don't play with runt packets.
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
2426aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(isize<sizeof(struct iphdr))
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return isize;
2456aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ip = (struct iphdr *) icp;
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Bail if this packet isn't TCP, or is an IP fragment */
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ip->protocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x3fff)) {
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Send as regular IP */
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if(ip->protocol != IPPROTO_TCP)
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			comp->sls_o_nontcp++;
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			comp->sls_o_tcp++;
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return isize;
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Extract TCP header */
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	th = (struct tcphdr *)(((unsigned char *)ip) + ip->ihl*4);
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hlen = ip->ihl*4 + th->doff*4;
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*  Bail if the TCP packet isn't `compressible' (i.e., ACK isn't set or
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *  some other control bit is set). Also uncompressible if
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *  it's a runt.
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(hlen > isize || th->syn || th->fin || th->rst ||
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    ! (th->ack)){
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* TCP connection stuff; send as regular IP */
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		comp->sls_o_tcp++;
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return isize;
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Packet is compressible -- we're going to send either a
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * COMPRESSED_TCP or UNCOMPRESSED_TCP packet.  Either way,
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * we need to locate (or create) the connection state.
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * States are kept in a circularly linked list with
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * xmit_oldest pointing to the end of the list.  The
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * list is kept in lru order by moving a state to the
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * head of the list whenever it is referenced.  Since
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * the list is short and, empirically, the connection
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * we want is almost always near the front, we locate
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * states via linear search.  If we don't find a state
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * for the datagram, the oldest state is (re-)used.
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for ( ; ; ) {
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if( ip->saddr == cs->cs_ip.saddr
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 && ip->daddr == cs->cs_ip.daddr
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 && th->source == cs->cs_tcp.source
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 && th->dest == cs->cs_tcp.dest)
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto found;
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* if current equal oldest, at end of list */
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ( cs == ocs )
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lcs = cs;
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cs = cs->next;
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		comp->sls_o_searches++;
2996403eab143205a45a5493166ff8bf7e3646f4a77Joe Perches	}
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Didn't find it -- re-use oldest cstate.  Send an
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * uncompressed packet that tells the other side what
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * connection number we're using for this conversation.
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Note that since the state list is circular, the oldest
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * state points to the newest and we only need to set
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * xmit_oldest to update the lru linkage.
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	comp->sls_o_misses++;
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	comp->xmit_oldest = lcs->cs_this;
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goto uncompressed;
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfound:
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Found it -- move to the front on the connection list.
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(lcs == ocs) {
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 		/* found at most recently used */
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (cs == ocs) {
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* found at least recently used */
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		comp->xmit_oldest = lcs->cs_this;
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* more than 2 elements */
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lcs->next = cs->next;
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cs->next = ocs->next;
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ocs->next = cs;
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Make sure that only what we expect to change changed.
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Check the following:
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * IP protocol version, header length & type of service.
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * The "Don't fragment" bit.
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * The time-to-live field.
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * The TCP header length.
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * IP options, if any.
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * TCP options, if any.
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * If any of these things are different between the previous &
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * current datagram, we send the current datagram `uncompressed'.
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	oth = &cs->cs_tcp;
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 || ip->tos != cs->cs_ip.tos
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 || (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000))
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 || ip->ttl != cs->cs_ip.ttl
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 || th->doff != cs->cs_tcp.doff
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0)
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)){
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto uncompressed;
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Figure out which of the changing fields changed.  The
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * receiver expects changes in the order: urgent, window,
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * ack, seq (the order minimizes the number of temporaries
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * needed in this section of code).
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(th->urg){
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		deltaS = ntohs(th->urg_ptr);
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cp = encode(cp,deltaS);
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		changes |= NEW_U;
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if(th->urg_ptr != oth->urg_ptr){
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* argh! URG not set but urp changed -- a sensible
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * implementation should never do this but RFC793
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * doesn't prohibit the change so we have to deal
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * with it. */
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto uncompressed;
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if((deltaS = ntohs(th->window) - ntohs(oth->window)) != 0){
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cp = encode(cp,deltaS);
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		changes |= NEW_W;
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if((deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L){
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if(deltaA > 0x0000ffff)
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto uncompressed;
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cp = encode(cp,deltaA);
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		changes |= NEW_A;
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if((deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L){
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if(deltaS > 0x0000ffff)
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto uncompressed;
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cp = encode(cp,deltaS);
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		changes |= NEW_S;
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch(changes){
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:	/* Nothing changed. If this packet contains data and the
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * last one didn't, this is probably a data packet following
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * an ack (normal on an interactive connection) and we send
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * it compressed.  Otherwise it's probably a retransmit,
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * retransmitted ack or window probe.  Send it uncompressed
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * in case the other side missed the compressed version.
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if(ip->tot_len != cs->cs_ip.tot_len &&
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   ntohs(cs->cs_ip.tot_len) == hlen)
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto uncompressed;
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SPECIAL_I:
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SPECIAL_D:
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* actual changes match one of our special case encodings --
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * send packet uncompressed.
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto uncompressed;
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case NEW_S|NEW_A:
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if(deltaS == deltaA &&
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    deltaS == ntohs(cs->cs_ip.tot_len) - hlen){
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* special case for echoed terminal traffic */
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			changes = SPECIAL_I;
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cp = new_seq;
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case NEW_S:
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if(deltaS == ntohs(cs->cs_ip.tot_len) - hlen){
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* special case for data xfer */
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			changes = SPECIAL_D;
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cp = new_seq;
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	deltaS = ntohs(ip->id) - ntohs(cs->cs_ip.id);
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(deltaS != 1){
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cp = encode(cp,deltaS);
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		changes |= NEW_I;
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(th->psh)
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		changes |= TCP_PUSH_BIT;
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Grab the cksum before we overwrite it below.  Then update our
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * state with this packet's header.
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4327cd61888d2ab9fa7e08205b18a24885e523df048Al Viro	csum = th->check;
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(&cs->cs_ip,ip,20);
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(&cs->cs_tcp,th,20);
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We want to use the original packet as our compressed packet.
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * (cp - new_seq) is the number of bytes we need for compressed
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * sequence numbers.  In addition we need one byte for the change
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * mask, one for the connection id and two for the tcp checksum.
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * So, (cp - new_seq) + 4 bytes of header are needed.
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	deltaS = cp - new_seq;
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(compress_cid == 0 || comp->xmit_current != cs->cs_this){
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cp = ocp;
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*cpp = ocp;
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*cp++ = changes | NEW_C;
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*cp++ = cs->cs_this;
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		comp->xmit_current = cs->cs_this;
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cp = ocp;
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*cpp = ocp;
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*cp++ = changes;
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4537cd61888d2ab9fa7e08205b18a24885e523df048Al Viro	*(__sum16 *)cp = csum;
4547cd61888d2ab9fa7e08205b18a24885e523df048Al Viro	cp += 2;
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* deltaS is now the size of the change section of the compressed header */
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(cp,new_seq,deltaS);	/* Write list of deltas */
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(cp+deltaS,icp+hlen,isize-hlen);
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	comp->sls_o_compressed++;
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ocp[0] |= SL_TYPE_COMPRESSED_TCP;
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return isize - hlen + deltaS + (cp - ocp);
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Update connection state cs & send uncompressed packet (i.e.,
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * a regular ip/tcp packet but with the 'conversation id' we hope
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * to use on future compressed packets in the protocol field).
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsuncompressed:
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(&cs->cs_ip,ip,20);
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(&cs->cs_tcp,th,20);
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ip->ihl > 5)
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  memcpy(cs->cs_ipopt, ip+1, ((ip->ihl) - 5) * 4);
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (th->doff > 5)
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  memcpy(cs->cs_tcpopt, th+1, ((th->doff) - 5) * 4);
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	comp->xmit_current = cs->cs_this;
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	comp->sls_o_uncompressed++;
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(ocp, icp, isize);
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*cpp = ocp;
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ocp[9] = cs->cs_this;
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ocp[0] |= SL_TYPE_UNCOMPRESSED_TCP;
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return isize;
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsslhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register int changes;
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	long x;
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register struct tcphdr *thp;
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register struct iphdr *ip;
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register struct cstate *cs;
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int len, hdrlen;
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *cp = icp;
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We've got a compressed packet; read the change byte */
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	comp->sls_i_compressed++;
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(isize < 3){
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		comp->sls_i_error++;
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	changes = *cp++;
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(changes & NEW_C){
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Make sure the state index is in range, then grab the state.
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * If we have a good state index, clear the 'discard' flag.
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		x = *cp++;	/* Read conn index */
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if(x < 0 || x > comp->rslot_limit)
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto bad;
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		comp->flags &=~ SLF_TOSS;
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		comp->recv_current = x;
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* this packet has an implicit state index.  If we've
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * had a line error since the last time we got an
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * explicit state index, we have to toss the packet. */
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if(comp->flags & SLF_TOSS){
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			comp->sls_i_tossed++;
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cs = &comp->rstate[comp->recv_current];
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	thp = &cs->cs_tcp;
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ip = &cs->cs_ip;
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5247cd61888d2ab9fa7e08205b18a24885e523df048Al Viro	thp->check = *(__sum16 *)cp;
5257cd61888d2ab9fa7e08205b18a24885e523df048Al Viro	cp += 2;
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	thp->psh = (changes & TCP_PUSH_BIT) ? 1 : 0;
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we can use the same number for the length of the saved header and
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the current one, because the packet wouldn't have been sent
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * as compressed unless the options were the same as the previous one
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hdrlen = ip->ihl * 4 + thp->doff * 4;
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch(changes & SPECIALS_MASK){
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SPECIAL_I:		/* Echoed terminal traffic */
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		register short i;
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i = ntohs(ip->tot_len) - hdrlen;
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		thp->ack_seq = htonl( ntohl(thp->ack_seq) + i);
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		thp->seq = htonl( ntohl(thp->seq) + i);
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SPECIAL_D:			/* Unidirectional data */
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		thp->seq = htonl( ntohl(thp->seq) +
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  ntohs(ip->tot_len) - hdrlen);
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if(changes & NEW_U){
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			thp->urg = 1;
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if((x = decode(&cp)) == -1) {
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto bad;
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			thp->urg_ptr = htons(x);
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			thp->urg = 0;
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if(changes & NEW_W){
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if((x = decode(&cp)) == -1) {
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto bad;
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			thp->window = htons( ntohs(thp->window) + x);
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if(changes & NEW_A){
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if((x = decode(&cp)) == -1) {
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto bad;
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			thp->ack_seq = htonl( ntohl(thp->ack_seq) + x);
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if(changes & NEW_S){
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if((x = decode(&cp)) == -1) {
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto bad;
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			thp->seq = htonl( ntohl(thp->seq) + x);
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(changes & NEW_I){
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if((x = decode(&cp)) == -1) {
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto bad;
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ip->id = htons (ntohs (ip->id) + x);
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ip->id = htons (ntohs (ip->id) + 1);
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * At this point, cp points to the first byte of data in the
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * packet.  Put the reconstructed TCP and IP headers back on the
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * packet.  Recalculate IP checksum (but not TCP checksum).
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = isize - (cp - icp);
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (len < 0)
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto bad;
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len += hdrlen;
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ip->tot_len = htons(len);
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ip->check = 0;
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memmove(icp + hdrlen, cp, len - hdrlen);
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cp = icp;
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(cp, ip, 20);
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cp += 20;
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ip->ihl > 5) {
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  memcpy(cp, cs->cs_ipopt, (ip->ihl - 5) * 4);
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  cp += (ip->ihl - 5) * 4;
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	put_unaligned(ip_fast_csum(icp, ip->ihl),
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      &((struct iphdr *)icp)->check);
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(cp, thp, 20);
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cp += 20;
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (thp->doff > 5) {
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  memcpy(cp, cs->cs_tcpopt, ((thp->doff) - 5) * 4);
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  cp += ((thp->doff) - 5) * 4;
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return len;
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsbad:
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	comp->sls_i_error++;
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return slhc_toss( comp );
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsslhc_remember(struct slcompress *comp, unsigned char *icp, int isize)
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register struct cstate *cs;
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned ihl;
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char index;
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(isize < 20) {
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* The packet is shorter than a legal IP header */
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		comp->sls_i_runt++;
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return slhc_toss( comp );
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Peek at the IP header's IHL field to find its length */
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ihl = icp[0] & 0xf;
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(ihl < 20 / 4){
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* The IP header length field is too small */
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		comp->sls_i_runt++;
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return slhc_toss( comp );
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	index = icp[9];
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	icp[9] = IPPROTO_TCP;
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ip_fast_csum(icp, ihl)) {
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Bad IP header checksum; discard */
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		comp->sls_i_badcheck++;
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return slhc_toss( comp );
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(index > comp->rslot_limit) {
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		comp->sls_i_error++;
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return slhc_toss(comp);
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Update local state */
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cs = &comp->rstate[comp->recv_current = index];
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	comp->flags &=~ SLF_TOSS;
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(&cs->cs_ip,icp,20);
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(&cs->cs_tcp,icp + ihl*4,20);
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ihl > 5)
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  memcpy(cs->cs_ipopt, icp + sizeof(struct iphdr), (ihl - 5) * 4);
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cs->cs_tcp.doff > 5)
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  memcpy(cs->cs_tcpopt, icp + ihl*4 + sizeof(struct tcphdr), (cs->cs_tcp.doff - 5) * 4);
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cs->cs_hsize = ihl*2 + cs->cs_tcp.doff*2;
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Put headers back on packet
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Neither header checksum is recalculated
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	comp->sls_i_uncompressed++;
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return isize;
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsslhc_toss(struct slcompress *comp)
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ( comp == NULLSLCOMPR )
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	comp->flags |= SLF_TOSS;
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else /* CONFIG_INET */
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsslhc_toss(struct slcompress *comp)
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_toss");
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  return -EINVAL;
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsslhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_uncompress");
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  return -EINVAL;
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsslhc_compress(struct slcompress *comp, unsigned char *icp, int isize,
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *ocp, unsigned char **cpp, int compress_cid)
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_compress");
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  return -EINVAL;
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsslhc_remember(struct slcompress *comp, unsigned char *icp, int isize)
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_remember");
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  return -EINVAL;
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsslhc_free(struct slcompress *comp)
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_free");
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct slcompress *
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsslhc_init(int rslots, int tslots)
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_init");
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  return NULL;
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7307f8a688e1e319fcc94dbed83a6ec82cea13f10b9Denis Kirjanov
7317f8a688e1e319fcc94dbed83a6ec82cea13f10b9Denis Kirjanov#endif /* CONFIG_INET */
7327f8a688e1e319fcc94dbed83a6ec82cea13f10b9Denis Kirjanov
7337f8a688e1e319fcc94dbed83a6ec82cea13f10b9Denis Kirjanov/* VJ header compression */
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(slhc_init);
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(slhc_free);
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(slhc_remember);
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(slhc_compress);
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(slhc_uncompress);
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(slhc_toss);
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("Dual BSD/GPL");
742