18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Routines to compress and uncompress tcp packets (for transmission 38c2ecf20Sopenharmony_ci * over low speed serial lines). 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 1989 Regents of the University of California. 68c2ecf20Sopenharmony_ci * All rights reserved. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms are permitted 98c2ecf20Sopenharmony_ci * provided that the above copyright notice and this paragraph are 108c2ecf20Sopenharmony_ci * duplicated in all such forms and that any documentation, 118c2ecf20Sopenharmony_ci * advertising materials, and other materials related to such 128c2ecf20Sopenharmony_ci * distribution and use acknowledge that the software was developed 138c2ecf20Sopenharmony_ci * by the University of California, Berkeley. The name of the 148c2ecf20Sopenharmony_ci * University may not be used to endorse or promote products derived 158c2ecf20Sopenharmony_ci * from this software without specific prior written permission. 168c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 178c2ecf20Sopenharmony_ci * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 188c2ecf20Sopenharmony_ci * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: 218c2ecf20Sopenharmony_ci * - Initial distribution. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * modified for KA9Q Internet Software Package by 258c2ecf20Sopenharmony_ci * Katie Stevens (dkstevens@ucdavis.edu) 268c2ecf20Sopenharmony_ci * University of California, Davis 278c2ecf20Sopenharmony_ci * Computing Services 288c2ecf20Sopenharmony_ci * - 01-31-90 initial adaptation (from 1.19) 298c2ecf20Sopenharmony_ci * PPP.05 02-15-90 [ks] 308c2ecf20Sopenharmony_ci * PPP.08 05-02-90 [ks] use PPP protocol field to signal compression 318c2ecf20Sopenharmony_ci * PPP.15 09-90 [ks] improve mbuf handling 328c2ecf20Sopenharmony_ci * PPP.16 11-02 [karn] substantially rewritten to use NOS facilities 338c2ecf20Sopenharmony_ci * 348c2ecf20Sopenharmony_ci * - Feb 1991 Bill_Simpson@um.cc.umich.edu 358c2ecf20Sopenharmony_ci * variable number of conversation slots 368c2ecf20Sopenharmony_ci * allow zero or one slots 378c2ecf20Sopenharmony_ci * separate routines 388c2ecf20Sopenharmony_ci * status display 398c2ecf20Sopenharmony_ci * - Jul 1994 Dmitry Gorodchanin 408c2ecf20Sopenharmony_ci * Fixes for memory leaks. 418c2ecf20Sopenharmony_ci * - Oct 1994 Dmitry Gorodchanin 428c2ecf20Sopenharmony_ci * Modularization. 438c2ecf20Sopenharmony_ci * - Jan 1995 Bjorn Ekwall 448c2ecf20Sopenharmony_ci * Use ip_fast_csum from ip.h 458c2ecf20Sopenharmony_ci * - July 1995 Christos A. Polyzols 468c2ecf20Sopenharmony_ci * Spotted bug in tcp option checking 478c2ecf20Sopenharmony_ci * 488c2ecf20Sopenharmony_ci * 498c2ecf20Sopenharmony_ci * This module is a difficult issue. It's clearly inet code but it's also clearly 508c2ecf20Sopenharmony_ci * driver code belonging close to PPP and SLIP 518c2ecf20Sopenharmony_ci */ 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#include <linux/module.h> 548c2ecf20Sopenharmony_ci#include <linux/slab.h> 558c2ecf20Sopenharmony_ci#include <linux/types.h> 568c2ecf20Sopenharmony_ci#include <linux/string.h> 578c2ecf20Sopenharmony_ci#include <linux/errno.h> 588c2ecf20Sopenharmony_ci#include <linux/kernel.h> 598c2ecf20Sopenharmony_ci#include <net/slhc_vj.h> 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci#ifdef CONFIG_INET 628c2ecf20Sopenharmony_ci/* Entire module is for IP only */ 638c2ecf20Sopenharmony_ci#include <linux/mm.h> 648c2ecf20Sopenharmony_ci#include <linux/socket.h> 658c2ecf20Sopenharmony_ci#include <linux/sockios.h> 668c2ecf20Sopenharmony_ci#include <linux/termios.h> 678c2ecf20Sopenharmony_ci#include <linux/in.h> 688c2ecf20Sopenharmony_ci#include <linux/fcntl.h> 698c2ecf20Sopenharmony_ci#include <linux/inet.h> 708c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 718c2ecf20Sopenharmony_ci#include <net/ip.h> 728c2ecf20Sopenharmony_ci#include <net/protocol.h> 738c2ecf20Sopenharmony_ci#include <net/icmp.h> 748c2ecf20Sopenharmony_ci#include <net/tcp.h> 758c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 768c2ecf20Sopenharmony_ci#include <net/sock.h> 778c2ecf20Sopenharmony_ci#include <linux/timer.h> 788c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 798c2ecf20Sopenharmony_ci#include <net/checksum.h> 808c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic unsigned char *encode(unsigned char *cp, unsigned short n); 838c2ecf20Sopenharmony_cistatic long decode(unsigned char **cpp); 848c2ecf20Sopenharmony_cistatic unsigned char * put16(unsigned char *cp, unsigned short x); 858c2ecf20Sopenharmony_cistatic unsigned short pull16(unsigned char **cpp); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci/* Allocate compression data structure 888c2ecf20Sopenharmony_ci * slots must be in range 0 to 255 (zero meaning no compression) 898c2ecf20Sopenharmony_ci * Returns pointer to structure or ERR_PTR() on error. 908c2ecf20Sopenharmony_ci */ 918c2ecf20Sopenharmony_cistruct slcompress * 928c2ecf20Sopenharmony_cislhc_init(int rslots, int tslots) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci short i; 958c2ecf20Sopenharmony_ci struct cstate *ts; 968c2ecf20Sopenharmony_ci struct slcompress *comp; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci if (rslots < 0 || rslots > 255 || tslots < 0 || tslots > 255) 998c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci comp = kzalloc(sizeof(struct slcompress), GFP_KERNEL); 1028c2ecf20Sopenharmony_ci if (! comp) 1038c2ecf20Sopenharmony_ci goto out_fail; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci if (rslots > 0) { 1068c2ecf20Sopenharmony_ci size_t rsize = rslots * sizeof(struct cstate); 1078c2ecf20Sopenharmony_ci comp->rstate = kzalloc(rsize, GFP_KERNEL); 1088c2ecf20Sopenharmony_ci if (! comp->rstate) 1098c2ecf20Sopenharmony_ci goto out_free; 1108c2ecf20Sopenharmony_ci comp->rslot_limit = rslots - 1; 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci if (tslots > 0) { 1148c2ecf20Sopenharmony_ci size_t tsize = tslots * sizeof(struct cstate); 1158c2ecf20Sopenharmony_ci comp->tstate = kzalloc(tsize, GFP_KERNEL); 1168c2ecf20Sopenharmony_ci if (! comp->tstate) 1178c2ecf20Sopenharmony_ci goto out_free2; 1188c2ecf20Sopenharmony_ci comp->tslot_limit = tslots - 1; 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci comp->xmit_oldest = 0; 1228c2ecf20Sopenharmony_ci comp->xmit_current = 255; 1238c2ecf20Sopenharmony_ci comp->recv_current = 255; 1248c2ecf20Sopenharmony_ci /* 1258c2ecf20Sopenharmony_ci * don't accept any packets with implicit index until we get 1268c2ecf20Sopenharmony_ci * one with an explicit index. Otherwise the uncompress code 1278c2ecf20Sopenharmony_ci * will try to use connection 255, which is almost certainly 1288c2ecf20Sopenharmony_ci * out of range 1298c2ecf20Sopenharmony_ci */ 1308c2ecf20Sopenharmony_ci comp->flags |= SLF_TOSS; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci if ( tslots > 0 ) { 1338c2ecf20Sopenharmony_ci ts = comp->tstate; 1348c2ecf20Sopenharmony_ci for(i = comp->tslot_limit; i > 0; --i){ 1358c2ecf20Sopenharmony_ci ts[i].cs_this = i; 1368c2ecf20Sopenharmony_ci ts[i].next = &(ts[i - 1]); 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci ts[0].next = &(ts[comp->tslot_limit]); 1398c2ecf20Sopenharmony_ci ts[0].cs_this = 0; 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci return comp; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ciout_free2: 1448c2ecf20Sopenharmony_ci kfree(comp->rstate); 1458c2ecf20Sopenharmony_ciout_free: 1468c2ecf20Sopenharmony_ci kfree(comp); 1478c2ecf20Sopenharmony_ciout_fail: 1488c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci/* Free a compression data structure */ 1538c2ecf20Sopenharmony_civoid 1548c2ecf20Sopenharmony_cislhc_free(struct slcompress *comp) 1558c2ecf20Sopenharmony_ci{ 1568c2ecf20Sopenharmony_ci if ( IS_ERR_OR_NULL(comp) ) 1578c2ecf20Sopenharmony_ci return; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci if ( comp->tstate != NULLSLSTATE ) 1608c2ecf20Sopenharmony_ci kfree( comp->tstate ); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci if ( comp->rstate != NULLSLSTATE ) 1638c2ecf20Sopenharmony_ci kfree( comp->rstate ); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci kfree( comp ); 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci/* Put a short in host order into a char array in network order */ 1708c2ecf20Sopenharmony_cistatic inline unsigned char * 1718c2ecf20Sopenharmony_ciput16(unsigned char *cp, unsigned short x) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci *cp++ = x >> 8; 1748c2ecf20Sopenharmony_ci *cp++ = x; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci return cp; 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci/* Encode a number */ 1818c2ecf20Sopenharmony_cistatic unsigned char * 1828c2ecf20Sopenharmony_ciencode(unsigned char *cp, unsigned short n) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci if(n >= 256 || n == 0){ 1858c2ecf20Sopenharmony_ci *cp++ = 0; 1868c2ecf20Sopenharmony_ci cp = put16(cp,n); 1878c2ecf20Sopenharmony_ci } else { 1888c2ecf20Sopenharmony_ci *cp++ = n; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci return cp; 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci/* Pull a 16-bit integer in host order from buffer in network byte order */ 1948c2ecf20Sopenharmony_cistatic unsigned short 1958c2ecf20Sopenharmony_cipull16(unsigned char **cpp) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci short rval; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci rval = *(*cpp)++; 2008c2ecf20Sopenharmony_ci rval <<= 8; 2018c2ecf20Sopenharmony_ci rval |= *(*cpp)++; 2028c2ecf20Sopenharmony_ci return rval; 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci/* Decode a number */ 2068c2ecf20Sopenharmony_cistatic long 2078c2ecf20Sopenharmony_cidecode(unsigned char **cpp) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci int x; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci x = *(*cpp)++; 2128c2ecf20Sopenharmony_ci if(x == 0){ 2138c2ecf20Sopenharmony_ci return pull16(cpp) & 0xffff; /* pull16 returns -1 on error */ 2148c2ecf20Sopenharmony_ci } else { 2158c2ecf20Sopenharmony_ci return x & 0xff; /* -1 if PULLCHAR returned error */ 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci/* 2208c2ecf20Sopenharmony_ci * icp and isize are the original packet. 2218c2ecf20Sopenharmony_ci * ocp is a place to put a copy if necessary. 2228c2ecf20Sopenharmony_ci * cpp is initially a pointer to icp. If the copy is used, 2238c2ecf20Sopenharmony_ci * change it to ocp. 2248c2ecf20Sopenharmony_ci */ 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ciint 2278c2ecf20Sopenharmony_cislhc_compress(struct slcompress *comp, unsigned char *icp, int isize, 2288c2ecf20Sopenharmony_ci unsigned char *ocp, unsigned char **cpp, int compress_cid) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci struct cstate *ocs = &(comp->tstate[comp->xmit_oldest]); 2318c2ecf20Sopenharmony_ci struct cstate *lcs = ocs; 2328c2ecf20Sopenharmony_ci struct cstate *cs = lcs->next; 2338c2ecf20Sopenharmony_ci unsigned long deltaS, deltaA; 2348c2ecf20Sopenharmony_ci short changes = 0; 2358c2ecf20Sopenharmony_ci int nlen, hlen; 2368c2ecf20Sopenharmony_ci unsigned char new_seq[16]; 2378c2ecf20Sopenharmony_ci unsigned char *cp = new_seq; 2388c2ecf20Sopenharmony_ci struct iphdr *ip; 2398c2ecf20Sopenharmony_ci struct tcphdr *th, *oth; 2408c2ecf20Sopenharmony_ci __sum16 csum; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci /* 2448c2ecf20Sopenharmony_ci * Don't play with runt packets. 2458c2ecf20Sopenharmony_ci */ 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if(isize<sizeof(struct iphdr)) 2488c2ecf20Sopenharmony_ci return isize; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci ip = (struct iphdr *) icp; 2518c2ecf20Sopenharmony_ci if (ip->version != 4 || ip->ihl < 5) 2528c2ecf20Sopenharmony_ci return isize; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci /* Bail if this packet isn't TCP, or is an IP fragment */ 2558c2ecf20Sopenharmony_ci if (ip->protocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x3fff)) { 2568c2ecf20Sopenharmony_ci /* Send as regular IP */ 2578c2ecf20Sopenharmony_ci if(ip->protocol != IPPROTO_TCP) 2588c2ecf20Sopenharmony_ci comp->sls_o_nontcp++; 2598c2ecf20Sopenharmony_ci else 2608c2ecf20Sopenharmony_ci comp->sls_o_tcp++; 2618c2ecf20Sopenharmony_ci return isize; 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci nlen = ip->ihl * 4; 2648c2ecf20Sopenharmony_ci if (isize < nlen + sizeof(*th)) 2658c2ecf20Sopenharmony_ci return isize; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci th = (struct tcphdr *)(icp + nlen); 2688c2ecf20Sopenharmony_ci if (th->doff < sizeof(struct tcphdr) / 4) 2698c2ecf20Sopenharmony_ci return isize; 2708c2ecf20Sopenharmony_ci hlen = nlen + th->doff * 4; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci /* Bail if the TCP packet isn't `compressible' (i.e., ACK isn't set or 2738c2ecf20Sopenharmony_ci * some other control bit is set). Also uncompressible if 2748c2ecf20Sopenharmony_ci * it's a runt. 2758c2ecf20Sopenharmony_ci */ 2768c2ecf20Sopenharmony_ci if(hlen > isize || th->syn || th->fin || th->rst || 2778c2ecf20Sopenharmony_ci ! (th->ack)){ 2788c2ecf20Sopenharmony_ci /* TCP connection stuff; send as regular IP */ 2798c2ecf20Sopenharmony_ci comp->sls_o_tcp++; 2808c2ecf20Sopenharmony_ci return isize; 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci /* 2838c2ecf20Sopenharmony_ci * Packet is compressible -- we're going to send either a 2848c2ecf20Sopenharmony_ci * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way, 2858c2ecf20Sopenharmony_ci * we need to locate (or create) the connection state. 2868c2ecf20Sopenharmony_ci * 2878c2ecf20Sopenharmony_ci * States are kept in a circularly linked list with 2888c2ecf20Sopenharmony_ci * xmit_oldest pointing to the end of the list. The 2898c2ecf20Sopenharmony_ci * list is kept in lru order by moving a state to the 2908c2ecf20Sopenharmony_ci * head of the list whenever it is referenced. Since 2918c2ecf20Sopenharmony_ci * the list is short and, empirically, the connection 2928c2ecf20Sopenharmony_ci * we want is almost always near the front, we locate 2938c2ecf20Sopenharmony_ci * states via linear search. If we don't find a state 2948c2ecf20Sopenharmony_ci * for the datagram, the oldest state is (re-)used. 2958c2ecf20Sopenharmony_ci */ 2968c2ecf20Sopenharmony_ci for ( ; ; ) { 2978c2ecf20Sopenharmony_ci if( ip->saddr == cs->cs_ip.saddr 2988c2ecf20Sopenharmony_ci && ip->daddr == cs->cs_ip.daddr 2998c2ecf20Sopenharmony_ci && th->source == cs->cs_tcp.source 3008c2ecf20Sopenharmony_ci && th->dest == cs->cs_tcp.dest) 3018c2ecf20Sopenharmony_ci goto found; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci /* if current equal oldest, at end of list */ 3048c2ecf20Sopenharmony_ci if ( cs == ocs ) 3058c2ecf20Sopenharmony_ci break; 3068c2ecf20Sopenharmony_ci lcs = cs; 3078c2ecf20Sopenharmony_ci cs = cs->next; 3088c2ecf20Sopenharmony_ci comp->sls_o_searches++; 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci /* 3118c2ecf20Sopenharmony_ci * Didn't find it -- re-use oldest cstate. Send an 3128c2ecf20Sopenharmony_ci * uncompressed packet that tells the other side what 3138c2ecf20Sopenharmony_ci * connection number we're using for this conversation. 3148c2ecf20Sopenharmony_ci * 3158c2ecf20Sopenharmony_ci * Note that since the state list is circular, the oldest 3168c2ecf20Sopenharmony_ci * state points to the newest and we only need to set 3178c2ecf20Sopenharmony_ci * xmit_oldest to update the lru linkage. 3188c2ecf20Sopenharmony_ci */ 3198c2ecf20Sopenharmony_ci comp->sls_o_misses++; 3208c2ecf20Sopenharmony_ci comp->xmit_oldest = lcs->cs_this; 3218c2ecf20Sopenharmony_ci goto uncompressed; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_cifound: 3248c2ecf20Sopenharmony_ci /* 3258c2ecf20Sopenharmony_ci * Found it -- move to the front on the connection list. 3268c2ecf20Sopenharmony_ci */ 3278c2ecf20Sopenharmony_ci if(lcs == ocs) { 3288c2ecf20Sopenharmony_ci /* found at most recently used */ 3298c2ecf20Sopenharmony_ci } else if (cs == ocs) { 3308c2ecf20Sopenharmony_ci /* found at least recently used */ 3318c2ecf20Sopenharmony_ci comp->xmit_oldest = lcs->cs_this; 3328c2ecf20Sopenharmony_ci } else { 3338c2ecf20Sopenharmony_ci /* more than 2 elements */ 3348c2ecf20Sopenharmony_ci lcs->next = cs->next; 3358c2ecf20Sopenharmony_ci cs->next = ocs->next; 3368c2ecf20Sopenharmony_ci ocs->next = cs; 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci /* 3408c2ecf20Sopenharmony_ci * Make sure that only what we expect to change changed. 3418c2ecf20Sopenharmony_ci * Check the following: 3428c2ecf20Sopenharmony_ci * IP protocol version, header length & type of service. 3438c2ecf20Sopenharmony_ci * The "Don't fragment" bit. 3448c2ecf20Sopenharmony_ci * The time-to-live field. 3458c2ecf20Sopenharmony_ci * The TCP header length. 3468c2ecf20Sopenharmony_ci * IP options, if any. 3478c2ecf20Sopenharmony_ci * TCP options, if any. 3488c2ecf20Sopenharmony_ci * If any of these things are different between the previous & 3498c2ecf20Sopenharmony_ci * current datagram, we send the current datagram `uncompressed'. 3508c2ecf20Sopenharmony_ci */ 3518c2ecf20Sopenharmony_ci oth = &cs->cs_tcp; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci if(ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl 3548c2ecf20Sopenharmony_ci || ip->tos != cs->cs_ip.tos 3558c2ecf20Sopenharmony_ci || (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000)) 3568c2ecf20Sopenharmony_ci || ip->ttl != cs->cs_ip.ttl 3578c2ecf20Sopenharmony_ci || th->doff != cs->cs_tcp.doff 3588c2ecf20Sopenharmony_ci || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) 3598c2ecf20Sopenharmony_ci || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)){ 3608c2ecf20Sopenharmony_ci goto uncompressed; 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci /* 3648c2ecf20Sopenharmony_ci * Figure out which of the changing fields changed. The 3658c2ecf20Sopenharmony_ci * receiver expects changes in the order: urgent, window, 3668c2ecf20Sopenharmony_ci * ack, seq (the order minimizes the number of temporaries 3678c2ecf20Sopenharmony_ci * needed in this section of code). 3688c2ecf20Sopenharmony_ci */ 3698c2ecf20Sopenharmony_ci if(th->urg){ 3708c2ecf20Sopenharmony_ci deltaS = ntohs(th->urg_ptr); 3718c2ecf20Sopenharmony_ci cp = encode(cp,deltaS); 3728c2ecf20Sopenharmony_ci changes |= NEW_U; 3738c2ecf20Sopenharmony_ci } else if(th->urg_ptr != oth->urg_ptr){ 3748c2ecf20Sopenharmony_ci /* argh! URG not set but urp changed -- a sensible 3758c2ecf20Sopenharmony_ci * implementation should never do this but RFC793 3768c2ecf20Sopenharmony_ci * doesn't prohibit the change so we have to deal 3778c2ecf20Sopenharmony_ci * with it. */ 3788c2ecf20Sopenharmony_ci goto uncompressed; 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci if((deltaS = ntohs(th->window) - ntohs(oth->window)) != 0){ 3818c2ecf20Sopenharmony_ci cp = encode(cp,deltaS); 3828c2ecf20Sopenharmony_ci changes |= NEW_W; 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci if((deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L){ 3858c2ecf20Sopenharmony_ci if(deltaA > 0x0000ffff) 3868c2ecf20Sopenharmony_ci goto uncompressed; 3878c2ecf20Sopenharmony_ci cp = encode(cp,deltaA); 3888c2ecf20Sopenharmony_ci changes |= NEW_A; 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci if((deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L){ 3918c2ecf20Sopenharmony_ci if(deltaS > 0x0000ffff) 3928c2ecf20Sopenharmony_ci goto uncompressed; 3938c2ecf20Sopenharmony_ci cp = encode(cp,deltaS); 3948c2ecf20Sopenharmony_ci changes |= NEW_S; 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci switch(changes){ 3988c2ecf20Sopenharmony_ci case 0: /* Nothing changed. If this packet contains data and the 3998c2ecf20Sopenharmony_ci * last one didn't, this is probably a data packet following 4008c2ecf20Sopenharmony_ci * an ack (normal on an interactive connection) and we send 4018c2ecf20Sopenharmony_ci * it compressed. Otherwise it's probably a retransmit, 4028c2ecf20Sopenharmony_ci * retransmitted ack or window probe. Send it uncompressed 4038c2ecf20Sopenharmony_ci * in case the other side missed the compressed version. 4048c2ecf20Sopenharmony_ci */ 4058c2ecf20Sopenharmony_ci if(ip->tot_len != cs->cs_ip.tot_len && 4068c2ecf20Sopenharmony_ci ntohs(cs->cs_ip.tot_len) == hlen) 4078c2ecf20Sopenharmony_ci break; 4088c2ecf20Sopenharmony_ci goto uncompressed; 4098c2ecf20Sopenharmony_ci case SPECIAL_I: 4108c2ecf20Sopenharmony_ci case SPECIAL_D: 4118c2ecf20Sopenharmony_ci /* actual changes match one of our special case encodings -- 4128c2ecf20Sopenharmony_ci * send packet uncompressed. 4138c2ecf20Sopenharmony_ci */ 4148c2ecf20Sopenharmony_ci goto uncompressed; 4158c2ecf20Sopenharmony_ci case NEW_S|NEW_A: 4168c2ecf20Sopenharmony_ci if(deltaS == deltaA && 4178c2ecf20Sopenharmony_ci deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ 4188c2ecf20Sopenharmony_ci /* special case for echoed terminal traffic */ 4198c2ecf20Sopenharmony_ci changes = SPECIAL_I; 4208c2ecf20Sopenharmony_ci cp = new_seq; 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci break; 4238c2ecf20Sopenharmony_ci case NEW_S: 4248c2ecf20Sopenharmony_ci if(deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ 4258c2ecf20Sopenharmony_ci /* special case for data xfer */ 4268c2ecf20Sopenharmony_ci changes = SPECIAL_D; 4278c2ecf20Sopenharmony_ci cp = new_seq; 4288c2ecf20Sopenharmony_ci } 4298c2ecf20Sopenharmony_ci break; 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci deltaS = ntohs(ip->id) - ntohs(cs->cs_ip.id); 4328c2ecf20Sopenharmony_ci if(deltaS != 1){ 4338c2ecf20Sopenharmony_ci cp = encode(cp,deltaS); 4348c2ecf20Sopenharmony_ci changes |= NEW_I; 4358c2ecf20Sopenharmony_ci } 4368c2ecf20Sopenharmony_ci if(th->psh) 4378c2ecf20Sopenharmony_ci changes |= TCP_PUSH_BIT; 4388c2ecf20Sopenharmony_ci /* Grab the cksum before we overwrite it below. Then update our 4398c2ecf20Sopenharmony_ci * state with this packet's header. 4408c2ecf20Sopenharmony_ci */ 4418c2ecf20Sopenharmony_ci csum = th->check; 4428c2ecf20Sopenharmony_ci memcpy(&cs->cs_ip,ip,20); 4438c2ecf20Sopenharmony_ci memcpy(&cs->cs_tcp,th,20); 4448c2ecf20Sopenharmony_ci /* We want to use the original packet as our compressed packet. 4458c2ecf20Sopenharmony_ci * (cp - new_seq) is the number of bytes we need for compressed 4468c2ecf20Sopenharmony_ci * sequence numbers. In addition we need one byte for the change 4478c2ecf20Sopenharmony_ci * mask, one for the connection id and two for the tcp checksum. 4488c2ecf20Sopenharmony_ci * So, (cp - new_seq) + 4 bytes of header are needed. 4498c2ecf20Sopenharmony_ci */ 4508c2ecf20Sopenharmony_ci deltaS = cp - new_seq; 4518c2ecf20Sopenharmony_ci if(compress_cid == 0 || comp->xmit_current != cs->cs_this){ 4528c2ecf20Sopenharmony_ci cp = ocp; 4538c2ecf20Sopenharmony_ci *cpp = ocp; 4548c2ecf20Sopenharmony_ci *cp++ = changes | NEW_C; 4558c2ecf20Sopenharmony_ci *cp++ = cs->cs_this; 4568c2ecf20Sopenharmony_ci comp->xmit_current = cs->cs_this; 4578c2ecf20Sopenharmony_ci } else { 4588c2ecf20Sopenharmony_ci cp = ocp; 4598c2ecf20Sopenharmony_ci *cpp = ocp; 4608c2ecf20Sopenharmony_ci *cp++ = changes; 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci *(__sum16 *)cp = csum; 4638c2ecf20Sopenharmony_ci cp += 2; 4648c2ecf20Sopenharmony_ci/* deltaS is now the size of the change section of the compressed header */ 4658c2ecf20Sopenharmony_ci memcpy(cp,new_seq,deltaS); /* Write list of deltas */ 4668c2ecf20Sopenharmony_ci memcpy(cp+deltaS,icp+hlen,isize-hlen); 4678c2ecf20Sopenharmony_ci comp->sls_o_compressed++; 4688c2ecf20Sopenharmony_ci ocp[0] |= SL_TYPE_COMPRESSED_TCP; 4698c2ecf20Sopenharmony_ci return isize - hlen + deltaS + (cp - ocp); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci /* Update connection state cs & send uncompressed packet (i.e., 4728c2ecf20Sopenharmony_ci * a regular ip/tcp packet but with the 'conversation id' we hope 4738c2ecf20Sopenharmony_ci * to use on future compressed packets in the protocol field). 4748c2ecf20Sopenharmony_ci */ 4758c2ecf20Sopenharmony_ciuncompressed: 4768c2ecf20Sopenharmony_ci memcpy(&cs->cs_ip,ip,20); 4778c2ecf20Sopenharmony_ci memcpy(&cs->cs_tcp,th,20); 4788c2ecf20Sopenharmony_ci if (ip->ihl > 5) 4798c2ecf20Sopenharmony_ci memcpy(cs->cs_ipopt, ip+1, ((ip->ihl) - 5) * 4); 4808c2ecf20Sopenharmony_ci if (th->doff > 5) 4818c2ecf20Sopenharmony_ci memcpy(cs->cs_tcpopt, th+1, ((th->doff) - 5) * 4); 4828c2ecf20Sopenharmony_ci comp->xmit_current = cs->cs_this; 4838c2ecf20Sopenharmony_ci comp->sls_o_uncompressed++; 4848c2ecf20Sopenharmony_ci memcpy(ocp, icp, isize); 4858c2ecf20Sopenharmony_ci *cpp = ocp; 4868c2ecf20Sopenharmony_ci ocp[9] = cs->cs_this; 4878c2ecf20Sopenharmony_ci ocp[0] |= SL_TYPE_UNCOMPRESSED_TCP; 4888c2ecf20Sopenharmony_ci return isize; 4898c2ecf20Sopenharmony_ci} 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ciint 4938c2ecf20Sopenharmony_cislhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) 4948c2ecf20Sopenharmony_ci{ 4958c2ecf20Sopenharmony_ci int changes; 4968c2ecf20Sopenharmony_ci long x; 4978c2ecf20Sopenharmony_ci struct tcphdr *thp; 4988c2ecf20Sopenharmony_ci struct iphdr *ip; 4998c2ecf20Sopenharmony_ci struct cstate *cs; 5008c2ecf20Sopenharmony_ci int len, hdrlen; 5018c2ecf20Sopenharmony_ci unsigned char *cp = icp; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci /* We've got a compressed packet; read the change byte */ 5048c2ecf20Sopenharmony_ci comp->sls_i_compressed++; 5058c2ecf20Sopenharmony_ci if(isize < 3){ 5068c2ecf20Sopenharmony_ci comp->sls_i_error++; 5078c2ecf20Sopenharmony_ci return 0; 5088c2ecf20Sopenharmony_ci } 5098c2ecf20Sopenharmony_ci changes = *cp++; 5108c2ecf20Sopenharmony_ci if(changes & NEW_C){ 5118c2ecf20Sopenharmony_ci /* Make sure the state index is in range, then grab the state. 5128c2ecf20Sopenharmony_ci * If we have a good state index, clear the 'discard' flag. 5138c2ecf20Sopenharmony_ci */ 5148c2ecf20Sopenharmony_ci x = *cp++; /* Read conn index */ 5158c2ecf20Sopenharmony_ci if(x < 0 || x > comp->rslot_limit) 5168c2ecf20Sopenharmony_ci goto bad; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci /* Check if the cstate is initialized */ 5198c2ecf20Sopenharmony_ci if (!comp->rstate[x].initialized) 5208c2ecf20Sopenharmony_ci goto bad; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci comp->flags &=~ SLF_TOSS; 5238c2ecf20Sopenharmony_ci comp->recv_current = x; 5248c2ecf20Sopenharmony_ci } else { 5258c2ecf20Sopenharmony_ci /* this packet has an implicit state index. If we've 5268c2ecf20Sopenharmony_ci * had a line error since the last time we got an 5278c2ecf20Sopenharmony_ci * explicit state index, we have to toss the packet. */ 5288c2ecf20Sopenharmony_ci if(comp->flags & SLF_TOSS){ 5298c2ecf20Sopenharmony_ci comp->sls_i_tossed++; 5308c2ecf20Sopenharmony_ci return 0; 5318c2ecf20Sopenharmony_ci } 5328c2ecf20Sopenharmony_ci } 5338c2ecf20Sopenharmony_ci cs = &comp->rstate[comp->recv_current]; 5348c2ecf20Sopenharmony_ci thp = &cs->cs_tcp; 5358c2ecf20Sopenharmony_ci ip = &cs->cs_ip; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci thp->check = *(__sum16 *)cp; 5388c2ecf20Sopenharmony_ci cp += 2; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci thp->psh = (changes & TCP_PUSH_BIT) ? 1 : 0; 5418c2ecf20Sopenharmony_ci/* 5428c2ecf20Sopenharmony_ci * we can use the same number for the length of the saved header and 5438c2ecf20Sopenharmony_ci * the current one, because the packet wouldn't have been sent 5448c2ecf20Sopenharmony_ci * as compressed unless the options were the same as the previous one 5458c2ecf20Sopenharmony_ci */ 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci hdrlen = ip->ihl * 4 + thp->doff * 4; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci switch(changes & SPECIALS_MASK){ 5508c2ecf20Sopenharmony_ci case SPECIAL_I: /* Echoed terminal traffic */ 5518c2ecf20Sopenharmony_ci { 5528c2ecf20Sopenharmony_ci short i; 5538c2ecf20Sopenharmony_ci i = ntohs(ip->tot_len) - hdrlen; 5548c2ecf20Sopenharmony_ci thp->ack_seq = htonl( ntohl(thp->ack_seq) + i); 5558c2ecf20Sopenharmony_ci thp->seq = htonl( ntohl(thp->seq) + i); 5568c2ecf20Sopenharmony_ci } 5578c2ecf20Sopenharmony_ci break; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci case SPECIAL_D: /* Unidirectional data */ 5608c2ecf20Sopenharmony_ci thp->seq = htonl( ntohl(thp->seq) + 5618c2ecf20Sopenharmony_ci ntohs(ip->tot_len) - hdrlen); 5628c2ecf20Sopenharmony_ci break; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci default: 5658c2ecf20Sopenharmony_ci if(changes & NEW_U){ 5668c2ecf20Sopenharmony_ci thp->urg = 1; 5678c2ecf20Sopenharmony_ci if((x = decode(&cp)) == -1) { 5688c2ecf20Sopenharmony_ci goto bad; 5698c2ecf20Sopenharmony_ci } 5708c2ecf20Sopenharmony_ci thp->urg_ptr = htons(x); 5718c2ecf20Sopenharmony_ci } else 5728c2ecf20Sopenharmony_ci thp->urg = 0; 5738c2ecf20Sopenharmony_ci if(changes & NEW_W){ 5748c2ecf20Sopenharmony_ci if((x = decode(&cp)) == -1) { 5758c2ecf20Sopenharmony_ci goto bad; 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci thp->window = htons( ntohs(thp->window) + x); 5788c2ecf20Sopenharmony_ci } 5798c2ecf20Sopenharmony_ci if(changes & NEW_A){ 5808c2ecf20Sopenharmony_ci if((x = decode(&cp)) == -1) { 5818c2ecf20Sopenharmony_ci goto bad; 5828c2ecf20Sopenharmony_ci } 5838c2ecf20Sopenharmony_ci thp->ack_seq = htonl( ntohl(thp->ack_seq) + x); 5848c2ecf20Sopenharmony_ci } 5858c2ecf20Sopenharmony_ci if(changes & NEW_S){ 5868c2ecf20Sopenharmony_ci if((x = decode(&cp)) == -1) { 5878c2ecf20Sopenharmony_ci goto bad; 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci thp->seq = htonl( ntohl(thp->seq) + x); 5908c2ecf20Sopenharmony_ci } 5918c2ecf20Sopenharmony_ci break; 5928c2ecf20Sopenharmony_ci } 5938c2ecf20Sopenharmony_ci if(changes & NEW_I){ 5948c2ecf20Sopenharmony_ci if((x = decode(&cp)) == -1) { 5958c2ecf20Sopenharmony_ci goto bad; 5968c2ecf20Sopenharmony_ci } 5978c2ecf20Sopenharmony_ci ip->id = htons (ntohs (ip->id) + x); 5988c2ecf20Sopenharmony_ci } else 5998c2ecf20Sopenharmony_ci ip->id = htons (ntohs (ip->id) + 1); 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci /* 6028c2ecf20Sopenharmony_ci * At this point, cp points to the first byte of data in the 6038c2ecf20Sopenharmony_ci * packet. Put the reconstructed TCP and IP headers back on the 6048c2ecf20Sopenharmony_ci * packet. Recalculate IP checksum (but not TCP checksum). 6058c2ecf20Sopenharmony_ci */ 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci len = isize - (cp - icp); 6088c2ecf20Sopenharmony_ci if (len < 0) 6098c2ecf20Sopenharmony_ci goto bad; 6108c2ecf20Sopenharmony_ci len += hdrlen; 6118c2ecf20Sopenharmony_ci ip->tot_len = htons(len); 6128c2ecf20Sopenharmony_ci ip->check = 0; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci memmove(icp + hdrlen, cp, len - hdrlen); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci cp = icp; 6178c2ecf20Sopenharmony_ci memcpy(cp, ip, 20); 6188c2ecf20Sopenharmony_ci cp += 20; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci if (ip->ihl > 5) { 6218c2ecf20Sopenharmony_ci memcpy(cp, cs->cs_ipopt, (ip->ihl - 5) * 4); 6228c2ecf20Sopenharmony_ci cp += (ip->ihl - 5) * 4; 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci put_unaligned(ip_fast_csum(icp, ip->ihl), 6268c2ecf20Sopenharmony_ci &((struct iphdr *)icp)->check); 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci memcpy(cp, thp, 20); 6298c2ecf20Sopenharmony_ci cp += 20; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci if (thp->doff > 5) { 6328c2ecf20Sopenharmony_ci memcpy(cp, cs->cs_tcpopt, ((thp->doff) - 5) * 4); 6338c2ecf20Sopenharmony_ci cp += ((thp->doff) - 5) * 4; 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci return len; 6378c2ecf20Sopenharmony_cibad: 6388c2ecf20Sopenharmony_ci comp->sls_i_error++; 6398c2ecf20Sopenharmony_ci return slhc_toss( comp ); 6408c2ecf20Sopenharmony_ci} 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ciint 6448c2ecf20Sopenharmony_cislhc_remember(struct slcompress *comp, unsigned char *icp, int isize) 6458c2ecf20Sopenharmony_ci{ 6468c2ecf20Sopenharmony_ci struct cstate *cs; 6478c2ecf20Sopenharmony_ci unsigned ihl; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci unsigned char index; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci if(isize < 20) { 6528c2ecf20Sopenharmony_ci /* The packet is shorter than a legal IP header */ 6538c2ecf20Sopenharmony_ci comp->sls_i_runt++; 6548c2ecf20Sopenharmony_ci return slhc_toss( comp ); 6558c2ecf20Sopenharmony_ci } 6568c2ecf20Sopenharmony_ci /* Peek at the IP header's IHL field to find its length */ 6578c2ecf20Sopenharmony_ci ihl = icp[0] & 0xf; 6588c2ecf20Sopenharmony_ci if(ihl < 20 / 4){ 6598c2ecf20Sopenharmony_ci /* The IP header length field is too small */ 6608c2ecf20Sopenharmony_ci comp->sls_i_runt++; 6618c2ecf20Sopenharmony_ci return slhc_toss( comp ); 6628c2ecf20Sopenharmony_ci } 6638c2ecf20Sopenharmony_ci index = icp[9]; 6648c2ecf20Sopenharmony_ci icp[9] = IPPROTO_TCP; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci if (ip_fast_csum(icp, ihl)) { 6678c2ecf20Sopenharmony_ci /* Bad IP header checksum; discard */ 6688c2ecf20Sopenharmony_ci comp->sls_i_badcheck++; 6698c2ecf20Sopenharmony_ci return slhc_toss( comp ); 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci if(index > comp->rslot_limit) { 6728c2ecf20Sopenharmony_ci comp->sls_i_error++; 6738c2ecf20Sopenharmony_ci return slhc_toss(comp); 6748c2ecf20Sopenharmony_ci } 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci /* Update local state */ 6778c2ecf20Sopenharmony_ci cs = &comp->rstate[comp->recv_current = index]; 6788c2ecf20Sopenharmony_ci comp->flags &=~ SLF_TOSS; 6798c2ecf20Sopenharmony_ci memcpy(&cs->cs_ip,icp,20); 6808c2ecf20Sopenharmony_ci memcpy(&cs->cs_tcp,icp + ihl*4,20); 6818c2ecf20Sopenharmony_ci if (ihl > 5) 6828c2ecf20Sopenharmony_ci memcpy(cs->cs_ipopt, icp + sizeof(struct iphdr), (ihl - 5) * 4); 6838c2ecf20Sopenharmony_ci if (cs->cs_tcp.doff > 5) 6848c2ecf20Sopenharmony_ci memcpy(cs->cs_tcpopt, icp + ihl*4 + sizeof(struct tcphdr), (cs->cs_tcp.doff - 5) * 4); 6858c2ecf20Sopenharmony_ci cs->cs_hsize = ihl*2 + cs->cs_tcp.doff*2; 6868c2ecf20Sopenharmony_ci cs->initialized = true; 6878c2ecf20Sopenharmony_ci /* Put headers back on packet 6888c2ecf20Sopenharmony_ci * Neither header checksum is recalculated 6898c2ecf20Sopenharmony_ci */ 6908c2ecf20Sopenharmony_ci comp->sls_i_uncompressed++; 6918c2ecf20Sopenharmony_ci return isize; 6928c2ecf20Sopenharmony_ci} 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ciint 6958c2ecf20Sopenharmony_cislhc_toss(struct slcompress *comp) 6968c2ecf20Sopenharmony_ci{ 6978c2ecf20Sopenharmony_ci if ( comp == NULLSLCOMPR ) 6988c2ecf20Sopenharmony_ci return 0; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci comp->flags |= SLF_TOSS; 7018c2ecf20Sopenharmony_ci return 0; 7028c2ecf20Sopenharmony_ci} 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci#else /* CONFIG_INET */ 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ciint 7078c2ecf20Sopenharmony_cislhc_toss(struct slcompress *comp) 7088c2ecf20Sopenharmony_ci{ 7098c2ecf20Sopenharmony_ci printk(KERN_DEBUG "Called IP function on non IP-system: slhc_toss"); 7108c2ecf20Sopenharmony_ci return -EINVAL; 7118c2ecf20Sopenharmony_ci} 7128c2ecf20Sopenharmony_ciint 7138c2ecf20Sopenharmony_cislhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) 7148c2ecf20Sopenharmony_ci{ 7158c2ecf20Sopenharmony_ci printk(KERN_DEBUG "Called IP function on non IP-system: slhc_uncompress"); 7168c2ecf20Sopenharmony_ci return -EINVAL; 7178c2ecf20Sopenharmony_ci} 7188c2ecf20Sopenharmony_ciint 7198c2ecf20Sopenharmony_cislhc_compress(struct slcompress *comp, unsigned char *icp, int isize, 7208c2ecf20Sopenharmony_ci unsigned char *ocp, unsigned char **cpp, int compress_cid) 7218c2ecf20Sopenharmony_ci{ 7228c2ecf20Sopenharmony_ci printk(KERN_DEBUG "Called IP function on non IP-system: slhc_compress"); 7238c2ecf20Sopenharmony_ci return -EINVAL; 7248c2ecf20Sopenharmony_ci} 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ciint 7278c2ecf20Sopenharmony_cislhc_remember(struct slcompress *comp, unsigned char *icp, int isize) 7288c2ecf20Sopenharmony_ci{ 7298c2ecf20Sopenharmony_ci printk(KERN_DEBUG "Called IP function on non IP-system: slhc_remember"); 7308c2ecf20Sopenharmony_ci return -EINVAL; 7318c2ecf20Sopenharmony_ci} 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_civoid 7348c2ecf20Sopenharmony_cislhc_free(struct slcompress *comp) 7358c2ecf20Sopenharmony_ci{ 7368c2ecf20Sopenharmony_ci printk(KERN_DEBUG "Called IP function on non IP-system: slhc_free"); 7378c2ecf20Sopenharmony_ci} 7388c2ecf20Sopenharmony_cistruct slcompress * 7398c2ecf20Sopenharmony_cislhc_init(int rslots, int tslots) 7408c2ecf20Sopenharmony_ci{ 7418c2ecf20Sopenharmony_ci printk(KERN_DEBUG "Called IP function on non IP-system: slhc_init"); 7428c2ecf20Sopenharmony_ci return NULL; 7438c2ecf20Sopenharmony_ci} 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci#endif /* CONFIG_INET */ 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci/* VJ header compression */ 7488c2ecf20Sopenharmony_ciEXPORT_SYMBOL(slhc_init); 7498c2ecf20Sopenharmony_ciEXPORT_SYMBOL(slhc_free); 7508c2ecf20Sopenharmony_ciEXPORT_SYMBOL(slhc_remember); 7518c2ecf20Sopenharmony_ciEXPORT_SYMBOL(slhc_compress); 7528c2ecf20Sopenharmony_ciEXPORT_SYMBOL(slhc_uncompress); 7538c2ecf20Sopenharmony_ciEXPORT_SYMBOL(slhc_toss); 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 756