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