📄 slhc.c
字号:
if((deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L){
if(deltaA > 0x0000ffff)
goto uncompressed;
cp = encode(cp,deltaA);
changes |= NEW_A;
}
if((deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L){
if(deltaS > 0x0000ffff)
goto uncompressed;
cp = encode(cp,deltaS);
changes |= NEW_S;
}
switch(changes){
case 0: /* Nothing changed. If this packet contains data and the
* last one didn't, this is probably a data packet following
* an ack (normal on an interactive connection) and we send
* it compressed. Otherwise it's probably a retransmit,
* retransmitted ack or window probe. Send it uncompressed
* in case the other side missed the compressed version.
*/
if(ip->tot_len != cs->cs_ip.tot_len &&
ntohs(cs->cs_ip.tot_len) == hlen)
break;
DPRINT(("comp: retrans\n"));
goto uncompressed;
break;
case SPECIAL_I:
case SPECIAL_D:
/* actual changes match one of our special case encodings --
* send packet uncompressed.
*/
DPRINT(("comp: special\n"));
goto uncompressed;
case NEW_S|NEW_A:
if(deltaS == deltaA &&
deltaS == ntohs(cs->cs_ip.tot_len) - hlen){
/* special case for echoed terminal traffic */
changes = SPECIAL_I;
cp = new_seq;
}
break;
case NEW_S:
if(deltaS == ntohs(cs->cs_ip.tot_len) - hlen){
/* special case for data xfer */
changes = SPECIAL_D;
cp = new_seq;
}
break;
}
deltaS = ntohs(ip->id) - ntohs(cs->cs_ip.id);
if(deltaS != 1){
cp = encode(cp,deltaS);
changes |= NEW_I;
}
if(th->psh)
changes |= TCP_PUSH_BIT;
/* Grab the cksum before we overwrite it below. Then update our
* state with this packet's header.
*/
deltaA = ntohs(th->check);
memcpy(&cs->cs_ip,ip,20);
memcpy(&cs->cs_tcp,th,20);
/* We want to use the original packet as our compressed packet.
* (cp - new_seq) is the number of bytes we need for compressed
* sequence numbers. In addition we need one byte for the change
* mask, one for the connection id and two for the tcp checksum.
* So, (cp - new_seq) + 4 bytes of header are needed.
*/
deltaS = cp - new_seq;
if(compress_cid == 0 || comp->xmit_current != cs->cs_this){
cp = ocp;
*cpp = ocp;
*cp++ = changes | NEW_C;
*cp++ = cs->cs_this;
comp->xmit_current = cs->cs_this;
} else {
cp = ocp;
*cpp = ocp;
*cp++ = changes;
}
cp = put16(cp,(short)deltaA); /* Write TCP checksum */
/* deltaS is now the size of the change section of the compressed header */
DPRINT(("comp: %x %x %x %d %d\n", icp, cp, new_seq, hlen, deltaS));
memcpy(cp,new_seq,deltaS); /* Write list of deltas */
memcpy(cp+deltaS,icp+hlen,isize-hlen);
comp->sls_o_compressed++;
ocp[0] |= SL_TYPE_COMPRESSED_TCP;
return isize - hlen + deltaS + (cp - ocp);
/* Update connection state cs & send uncompressed packet (i.e.,
* a regular ip/tcp packet but with the 'conversation id' we hope
* to use on future compressed packets in the protocol field).
*/
uncompressed:
memcpy(&cs->cs_ip,ip,20);
memcpy(&cs->cs_tcp,th,20);
if (ip->ihl > 5)
memcpy(cs->cs_ipopt, ip+1, ((ip->ihl) - 5) * 4);
if (th->doff > 5)
memcpy(cs->cs_tcpopt, th+1, ((th->doff) - 5) * 4);
comp->xmit_current = cs->cs_this;
comp->sls_o_uncompressed++;
memcpy(ocp, icp, isize);
*cpp = ocp;
ocp[9] = cs->cs_this;
ocp[0] |= SL_TYPE_UNCOMPRESSED_TCP;
return isize;
}
int
slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)
{
register int changes;
long x;
register struct tcphdr *thp;
register struct iphdr *ip;
register struct cstate *cs;
int len, hdrlen;
unsigned char *cp = icp;
/* We've got a compressed packet; read the change byte */
comp->sls_i_compressed++;
if(isize < 3){
comp->sls_i_error++;
DPRINT(("uncomp: runt\n"));
return 0;
}
changes = *cp++;
if(changes & NEW_C){
/* Make sure the state index is in range, then grab the state.
* If we have a good state index, clear the 'discard' flag.
*/
x = *cp++; /* Read conn index */
if(x < 0 || x > comp->rslot_limit)
goto bad;
comp->flags &=~ SLF_TOSS;
comp->recv_current = x;
} else {
/* this packet has an implicit state index. If we've
* had a line error since the last time we got an
* explicit state index, we have to toss the packet. */
if(comp->flags & SLF_TOSS){
comp->sls_i_tossed++;
DPRINT(("uncomp: toss\n"));
return 0;
}
}
cs = &comp->rstate[comp->recv_current];
thp = &cs->cs_tcp;
ip = &cs->cs_ip;
if((x = pull16(&cp)) == -1) { /* Read the TCP checksum */
DPRINT(("uncomp: bad tcp chk\n"));
goto bad;
}
thp->check = htons(x);
thp->psh = (changes & TCP_PUSH_BIT) ? 1 : 0;
/*
* we can use the same number for the length of the saved header and
* the current one, because the packet wouldn't have been sent
* as compressed unless the options were the same as the previous one
*/
hdrlen = ip->ihl * 4 + thp->doff * 4;
switch(changes & SPECIALS_MASK){
case SPECIAL_I: /* Echoed terminal traffic */
{
register short i;
i = ntohs(ip->tot_len) - hdrlen;
thp->ack_seq = htonl( ntohl(thp->ack_seq) + i);
thp->seq = htonl( ntohl(thp->seq) + i);
}
break;
case SPECIAL_D: /* Unidirectional data */
thp->seq = htonl( ntohl(thp->seq) +
ntohs(ip->tot_len) - hdrlen);
break;
default:
if(changes & NEW_U){
thp->urg = 1;
if((x = decode(&cp)) == -1) {
DPRINT(("uncomp: bad U\n"));
goto bad;
}
thp->urg_ptr = htons(x);
} else
thp->urg = 0;
if(changes & NEW_W){
if((x = decode(&cp)) == -1) {
DPRINT(("uncomp: bad W\n"));
goto bad;
}
thp->window = htons( ntohs(thp->window) + x);
}
if(changes & NEW_A){
if((x = decode(&cp)) == -1) {
DPRINT(("uncomp: bad A\n"));
goto bad;
}
thp->ack_seq = htonl( ntohl(thp->ack_seq) + x);
}
if(changes & NEW_S){
if((x = decode(&cp)) == -1) {
DPRINT(("uncomp: bad S\n"));
goto bad;
}
thp->seq = htonl( ntohl(thp->seq) + x);
}
break;
}
if(changes & NEW_I){
if((x = decode(&cp)) == -1) {
DPRINT(("uncomp: bad I\n"));
goto bad;
}
ip->id = htons (ntohs (ip->id) + x);
} else
ip->id = htons (ntohs (ip->id) + 1);
/*
* At this point, cp points to the first byte of data in the
* packet. Put the reconstructed TCP and IP headers back on the
* packet. Recalculate IP checksum (but not TCP checksum).
*/
len = isize - (cp - icp);
if (len < 0)
goto bad;
len += hdrlen;
ip->tot_len = htons(len);
ip->check = 0;
DPRINT(("uncomp: %d %d %d %d\n", cp - icp, hdrlen, isize, len));
memmove(icp + hdrlen, cp, len - hdrlen);
cp = icp;
memcpy(cp, ip, 20);
cp += 20;
if (ip->ihl > 5) {
memcpy(cp, cs->cs_ipopt, ((ip->ihl) - 5) * 4);
cp += ((ip->ihl) - 5) * 4;
}
((struct iphdr *)icp)->check = ip_csum((struct iphdr*)icp);
memcpy(cp, thp, 20);
cp += 20;
if (thp->doff > 5) {
memcpy(cp, cs->cs_tcpopt, ((thp->doff) - 5) * 4);
cp += ((thp->doff) - 5) * 4;
}
if (inet_debug == DBG_SLIP) printk("\runcomp: change %x len %d\n", changes, len);
return len;
bad:
comp->sls_i_error++;
return slhc_toss( comp );
}
int
slhc_remember(struct slcompress *comp, unsigned char *icp, int isize)
{
register struct cstate *cs;
short ip_len;
struct iphdr *ip;
struct tcphdr *thp;
unsigned char index;
if(isize < 20) {
/* The packet is shorter than a legal IP header */
comp->sls_i_runt++;
return slhc_toss( comp );
}
/* Sneak a peek at the IP header's IHL field to find its length */
ip_len = (icp[0] & 0xf) << 2;
if(ip_len < 20){
/* The IP header length field is too small */
comp->sls_i_runt++;
return slhc_toss( comp );
}
index = icp[9];
icp[9] = IPPROTO_TCP;
ip = (struct iphdr *) icp;
if (ip_csum(ip)) {
/* Bad IP header checksum; discard */
comp->sls_i_badcheck++;
return slhc_toss( comp );
}
thp = (struct tcphdr *)(((unsigned char *)ip) + ip->ihl*4);
if(index > comp->rslot_limit) {
comp->sls_i_error++;
return slhc_toss(comp);
}
/* Update local state */
cs = &comp->rstate[comp->recv_current = index];
comp->flags &=~ SLF_TOSS;
memcpy(&cs->cs_ip,ip,20);
memcpy(&cs->cs_tcp,thp,20);
if (ip->ihl > 5)
memcpy(cs->cs_ipopt, ip+1, ((ip->ihl) - 5) * 4);
if (thp->doff > 5)
memcpy(cs->cs_tcpopt, thp+1, ((thp->doff) - 5) * 4);
cs->cs_hsize = ip->ihl*2 + thp->doff*2;
/* Put headers back on packet
* Neither header checksum is recalculated
*/
comp->sls_i_uncompressed++;
return isize;
}
int
slhc_toss(struct slcompress *comp)
{
if ( comp == NULLSLCOMPR )
return 0;
comp->flags |= SLF_TOSS;
return 0;
}
void slhc_i_status(struct slcompress *comp)
{
if (comp != NULLSLCOMPR) {
printk("\t%ld Cmp, %ld Uncmp, %ld Bad, %ld Tossed\n",
comp->sls_i_compressed,
comp->sls_i_uncompressed,
comp->sls_i_error,
comp->sls_i_tossed);
}
}
void slhc_o_status(struct slcompress *comp)
{
if (comp != NULLSLCOMPR) {
printk("\t%ld Cmp, %ld Uncmp, %ld AsIs, %ld NotTCP\n",
comp->sls_o_compressed,
comp->sls_o_uncompressed,
comp->sls_o_tcp,
comp->sls_o_nontcp);
printk("\t%10ld Searches, %10ld Misses\n",
comp->sls_o_searches,
comp->sls_o_misses);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -