📄 vjcomp.c
字号:
/*
* FILENAME: vjcomp.c
*
* Copyright 1997- 2001 By InterNiche Technologies Inc. All rights reserved
*
* The VJ TCP/IP header compression code.
* Routines to compress and uncompess tcp/ip headers (for transmission
* over low speed serial lines).
*
* MODULE: PPP
*
* ROUTINES: vj_compress_init(), sifvjcomp(), match_connection(),
* ROUTINES: vj_compress_tcp(), vj_uncompress_tcp(),
* ROUTINES: vj_uncompress_tcp_part(),
*
* PORTABLE: yes
*/
/* Additional Copyrights: */
/* Portions Copyright 1996 by NetPort Software, All rights reserved
* Portions Copyright (c) 1989 The Regents of the University of
* California. All rights reserved. Redistribution and use in source
* and binary forms, with or without modification, are permitted
* provided that the following conditions are met: 1. Redistributions
* of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution. 3. All
* advertising materials mentioning features or use of this software
* must display the following acknowledgement: This product includes
* software developed by the University of California, Berkeley and
* its contributors. 4. Neither the name of the University nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND
* CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "ppp_port.h"
#ifdef PPP_VJC /* whole file can be ifdeffed out */
#include "ppp_port.h"
#include "mppp.h"
#include "tcpapp.h"
#ifdef MINI_TCP
#include "../mtcp/mtcp.h"
#else
#include "tcp.h"
#endif
#ifndef IPPROTO_TCP
#define IPPROTO_TCP 6
#endif
/* Undef the item based version of TCP offset macro and replace with
* pointer based version for VJ code:
*/
#undef GET_TH_OFF
#define GET_TH_OFF(th) (th->th_doff >> 4)
/* FUNCTION: vj_compress_init()
*
* PARAM1: struct slcompress * comp
* PARAM2: u_char maxslotindex
*
* RETURNS: void
*/
void
vj_compress_init(struct slcompress * comp, u_char maxslotindex)
{
unsigned i;
struct cstate * tstate = comp->tstate;
MEMSET(comp, 0, sizeof(*comp));
if (maxslotindex > MAX_STATES - 1)
maxslotindex = MAX_STATES - 1;
for (i = maxslotindex; i > 0; --i)
{
tstate[i].cs_id = (u_char)i;
tstate[i].cs_next = &tstate[i - 1];
}
tstate[0].cs_next = &tstate[maxslotindex];
tstate[0].cs_id = 0;
comp->last_cs = &tstate[0];
comp->last_recv = 255;
comp->last_xmit = 255;
comp->flags = SLF_TOSS;
}
/* FUNCTION: sifvjcomp()
*
* sifvjcomp - config tcp header compression
*
*
* PARAM1: M_PPP mppp
* PARAM2: int vjcomp (bool) negitiated VJ comp
* PARAM3: u_char maxslotindex number of VJ slots
* PARAM4: int cidcomp
*
* RETURNS:
*/
int
sifvjcomp(M_PPP mppp, int vjcomp, u_char maxslotindex, int cidcomp)
{
int x; /* local copy of sc_flags */
/* set bits in sc_flags based on passed parms */
x = mppp->sc_flags;
if(vjcomp)
x |= SC_COMP_TCP;
else
x &= ~SC_COMP_TCP;
if(cidcomp)
x &= ~SC_NO_TCP_CCID;
else
x |= SC_NO_TCP_CCID;
mppp->sc_flags = x;
if(vjcomp || cidcomp)
vj_compress_init( &(mppp->sc_comp), maxslotindex);
return 1;
}
#ifndef SL_NO_STATS
#define INCR(counter) ++comp->counter;
#else
#define INCR(counter)
#endif
/* ENCODE encodes a number that is known to be non-zero. ENCODEZ
* checks for zero (since zero has to be encoded in the long, 3 byte
* form).
*/
#define ENCODE(n) { \
if ((u_short)(n) >= 256) { \
*cp++ = 0; \
cp[1] = (u_char)(n); \
cp[0] = (u_char)((n) >> 8); \
cp += 2; \
} else { \
*cp++ = (u_char)(n); \
} \
}
#define ENCODEZ(n) { \
if ((u_short)(n) >= 256 || (u_short)(n) == 0) { \
*cp++ = 0; \
cp[1] = (u_char)(n); \
cp[0] = (u_char)((n) >> 8); \
cp += 2; \
} else { \
*cp++ = (u_char)(n); \
} \
}
#define DECODEL(f) { \
if (*cp == 0) {\
(f) = htonl(ntohl(f) + (((u_long)cp[1] << 8) | cp[2])); \
cp += 3; \
} else { \
(f) = htonl(ntohl(f) + (u_long)*cp); \
cp++; \
} \
}
#define DECODES(f) { \
if (*cp == 0) {\
(f) = htons(ntohs(f) + ((cp[1] << 8) | cp[2])); \
cp += 3; \
} else { \
(f) = htons(ntohs(f) + (u_short)(*cp)); \
cp++; \
} \
}
#define DECODEU(f) { \
if (*cp == 0) { \
(f) = htons((cp[1] << 8) | cp[2]); \
cp += 3; \
} else { \
(f) = htons((u_short)(*cp)); \
cp++; \
} \
}
/* FUNCTION: match_connection()
*
* match_connection() - return TRUE if passed state matches
* passedIP packet, else FALSE
*
* PARAM1: struct ip * ip
* PARAM2: struct cstate * cs
*
* RETURNS: return TRUE if passed state matches passed IP
* packet, else FALSE
*/
static int
match_connection(struct ip * ip, struct cstate * cs)
{
struct tcphdr * th;
struct tcphdr * tmp;
/* check IP addresses */
if (ip->ip_src != cs->slcs_u.csu_ip.ip_src)
return FALSE;
if (ip->ip_dest != cs->slcs_u.csu_ip.ip_dest)
return FALSE;
/* check TCP ports */
th = (struct tcphdr *)(ip + 1);
tmp = (struct tcphdr*)(&cs->slcs_u.csu_ip + 1);
if (th->th_sport != tmp->th_sport)
return FALSE;
if (th->th_dport != tmp->th_dport)
return FALSE;
return TRUE; /* no test failed, it's a match */
}
/* FUNCTION: vj_compress_tcp()
*
* PARAM1: u_char ** buf
* PARAM2: unsigned * buflen
* PARAM3: struct ip * ip
* PARAM4: struct slcompress * comp
* PARAM5: int compress_cid
*
* RETURNS:
*/
u_char
vj_compress_tcp(u_char ** buf,
unsigned * buflen,
struct vj_ip * ip,
struct slcompress * comp,
int compress_cid)
{
struct cstate * cs = comp->last_cs->cs_next;
unsigned hlen = (ip->ip_ver_ihl & 0x0F);
struct tcphdr * oth;
struct tcphdr * th;
u_long deltaS, deltaA;
unsigned changes = 0;
u_char new_seq[16];
u_char * cp = new_seq;
/*
* Bail if this is an IP fragment or if the TCP packet isn't
* `compressible' (i.e., ACK isn't set or some other control bit is
* set). (We assume that the caller has already made sure the
* packet is IP proto TCP).
*/
if ((ip->ip_flgs_foff & htons(0x3fff)) || *buflen < 40)
return (PPP_IP);
th = (struct tcphdr *)(ip+1);
if ((th->th_flags & (TH_SYN|TH_FIN|TH_RST|TH_ACK)) != TH_ACK)
return (PPP_IP);
/*
* Packet is compressible -- we're going to send either a
* COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way we need
* to locate (or create) the connection state. Special case the
* most recently used connection since it's most likely to be used
* again & we don't have to do any reordering if it's used.
*/
INCR(sls_packets)
if (!match_connection((struct ip *)ip, cs))
{
/*
* Wasn't the first -- search for it.
*
* States are kept in a circularly linked list with
* last_cs pointing to the end of the list. The
* list is kept in lru order by moving a state to the
* head of the list whenever it is referenced. Since
* the list is short and, empirically, the connection
* we want is almost always near the front, we locate
* states via linear search. If we don't find a state
* for the datagram, the oldest state is (re-)used.
*/
struct cstate * lcs;
struct cstate * lastcs = comp->last_cs;
do
{
lcs = cs; cs = cs->cs_next;
INCR(sls_searches)
if (match_connection((struct ip *)ip, cs))
goto found;
} while (cs != lastcs);
/*
* Didn't find it -- re-use oldest cstate. Send an
* uncompressed packet that tells the other side what
* connection number we're using for this conversation.
* Note that since the state list is circular, the oldest
* state points to the newest and we only need to set
* last_cs to update the lru linkage.
*/
INCR(sls_misses)
comp->last_cs = lcs;
hlen += GET_TH_OFF(th);
hlen <<= 2;
if (hlen > *buflen)
return (PPP_IP);
goto uncompressed;
found:
/*
* Found it -- move to the front on the connection list.
*/
if (cs == lastcs)
comp->last_cs = lcs;
else
{
lcs->cs_next = cs->cs_next;
cs->cs_next = lastcs->cs_next;
lastcs->cs_next = cs;
}
}
/*
* Make sure that only what we expect to change changed. The first
* set of `ifs' below checks the IP protocol version, header length &
* type of service. The 2nd checks the "Don't fragment" bit.
* The 3rd line checks the time-to-live and protocol (the protocol
* check is unnecessary but costless). The 4th line checks the TCP
* header length. The 5th line checks IP options, if any. The 6th
* line checks TCP options, if any. If any of these things are
* different between the previous & current datagram, we send the
* current datagram `uncompressed'.
*/
oth = (struct tcphdr *)(&cs->slcs_u.csu_ip + 1);
deltaS = hlen;
hlen += GET_TH_OFF(th);
hlen <<= 2;
if (hlen > *buflen)
return (PPP_IP);
if (((u_short *)ip)[0] != ((u_short *)&cs->slcs_u.csu_ip)[0])
goto uncompressed;
if (((u_short *)ip)[3] != ((u_short *)&cs->slcs_u.csu_ip)[3])
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -