1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * Copyright (c) 2000 by Sun Microsystems, Inc. 3*7c478bd9Sstevel@tonic-gate * All rights reserved. 4*7c478bd9Sstevel@tonic-gate * 5*7c478bd9Sstevel@tonic-gate * Routines to compress and uncompess tcp packets (for transmission 6*7c478bd9Sstevel@tonic-gate * over low speed serial lines. 7*7c478bd9Sstevel@tonic-gate * 8*7c478bd9Sstevel@tonic-gate * Copyright (c) 1989 Regents of the University of California. 9*7c478bd9Sstevel@tonic-gate * All rights reserved. 10*7c478bd9Sstevel@tonic-gate * 11*7c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms are permitted 12*7c478bd9Sstevel@tonic-gate * provided that the above copyright notice and this paragraph are 13*7c478bd9Sstevel@tonic-gate * duplicated in all such forms and that any documentation, 14*7c478bd9Sstevel@tonic-gate * advertising materials, and other materials related to such 15*7c478bd9Sstevel@tonic-gate * distribution and use acknowledge that the software was developed 16*7c478bd9Sstevel@tonic-gate * by the University of California, Berkeley. The name of the 17*7c478bd9Sstevel@tonic-gate * University may not be used to endorse or promote products derived 18*7c478bd9Sstevel@tonic-gate * from this software without specific prior written permission. 19*7c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 20*7c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 21*7c478bd9Sstevel@tonic-gate * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 22*7c478bd9Sstevel@tonic-gate * 23*7c478bd9Sstevel@tonic-gate * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: 24*7c478bd9Sstevel@tonic-gate * - Initial distribution. 25*7c478bd9Sstevel@tonic-gate * 26*7c478bd9Sstevel@tonic-gate * Modified June 1993 by Paul Mackerras, paulus@cs.anu.edu.au, 27*7c478bd9Sstevel@tonic-gate * so that the entire packet being decompressed doesn't have 28*7c478bd9Sstevel@tonic-gate * to be in contiguous memory (just the compressed header). 29*7c478bd9Sstevel@tonic-gate */ 30*7c478bd9Sstevel@tonic-gate 31*7c478bd9Sstevel@tonic-gate /* 32*7c478bd9Sstevel@tonic-gate * This version is used under STREAMS in Solaris 2 33*7c478bd9Sstevel@tonic-gate * 34*7c478bd9Sstevel@tonic-gate * $Id: vjcompress.c,v 1.10 1999/09/15 23:49:06 masputra Exp $ 35*7c478bd9Sstevel@tonic-gate */ 36*7c478bd9Sstevel@tonic-gate 37*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/byteorder.h> /* for ntohl, etc. */ 40*7c478bd9Sstevel@tonic-gate #include <sys/systm.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 42*7c478bd9Sstevel@tonic-gate 43*7c478bd9Sstevel@tonic-gate #include <netinet/in.h> 44*7c478bd9Sstevel@tonic-gate #include <netinet/in_systm.h> 45*7c478bd9Sstevel@tonic-gate #include <netinet/ip.h> 46*7c478bd9Sstevel@tonic-gate #include <netinet/tcp.h> 47*7c478bd9Sstevel@tonic-gate 48*7c478bd9Sstevel@tonic-gate #include <net/ppp_defs.h> 49*7c478bd9Sstevel@tonic-gate #include <net/vjcompress.h> 50*7c478bd9Sstevel@tonic-gate 51*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 52*7c478bd9Sstevel@tonic-gate 53*7c478bd9Sstevel@tonic-gate #ifndef VJ_NO_STATS 54*7c478bd9Sstevel@tonic-gate #define INCR(counter) ++comp->stats.counter 55*7c478bd9Sstevel@tonic-gate #else 56*7c478bd9Sstevel@tonic-gate #define INCR(counter) 57*7c478bd9Sstevel@tonic-gate #endif 58*7c478bd9Sstevel@tonic-gate 59*7c478bd9Sstevel@tonic-gate #define BCMP(p1, p2, n) bcmp((char *)(p1), (char *)(p2), (unsigned int)(n)) 60*7c478bd9Sstevel@tonic-gate 61*7c478bd9Sstevel@tonic-gate #undef BCOPY 62*7c478bd9Sstevel@tonic-gate #define BCOPY(p1, p2, n) bcopy((char *)(p1), (char *)(p2), (unsigned int)(n)) 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate /* 65*7c478bd9Sstevel@tonic-gate * I'd like to use offsetof(struct ip,ip_hl) and offsetof(struct 66*7c478bd9Sstevel@tonic-gate * tcp,th_off), but these are bitfields. 67*7c478bd9Sstevel@tonic-gate */ 68*7c478bd9Sstevel@tonic-gate #define getip_hl(bp) (((uchar_t *)bp)[0] & 0x0F) 69*7c478bd9Sstevel@tonic-gate #define getth_off(bp) (((uchar_t *)bp)[12] >> 4) 70*7c478bd9Sstevel@tonic-gate #define getip_p(bp) (((uchar_t *)bp)[offsetof(struct ip, ip_p)]) 71*7c478bd9Sstevel@tonic-gate #define setip_p(bp, v) (((uchar_t *)bp)[offsetof(struct ip, ip_p)] = (v)) 72*7c478bd9Sstevel@tonic-gate 73*7c478bd9Sstevel@tonic-gate /* 74*7c478bd9Sstevel@tonic-gate * vj_compress_init() 75*7c478bd9Sstevel@tonic-gate */ 76*7c478bd9Sstevel@tonic-gate void 77*7c478bd9Sstevel@tonic-gate vj_compress_init(struct vjcompress *comp, int max_state) 78*7c478bd9Sstevel@tonic-gate { 79*7c478bd9Sstevel@tonic-gate register uint_t i; 80*7c478bd9Sstevel@tonic-gate register struct cstate *tstate = comp->tstate; 81*7c478bd9Sstevel@tonic-gate 82*7c478bd9Sstevel@tonic-gate if (max_state == -1) { 83*7c478bd9Sstevel@tonic-gate max_state = MAX_STATES - 1; 84*7c478bd9Sstevel@tonic-gate } 85*7c478bd9Sstevel@tonic-gate 86*7c478bd9Sstevel@tonic-gate bzero((char *)comp, sizeof (*comp)); 87*7c478bd9Sstevel@tonic-gate 88*7c478bd9Sstevel@tonic-gate for (i = max_state; i > 0; --i) { 89*7c478bd9Sstevel@tonic-gate tstate[i].cs_id = i & 0xff; 90*7c478bd9Sstevel@tonic-gate tstate[i].cs_next = &tstate[i - 1]; 91*7c478bd9Sstevel@tonic-gate } 92*7c478bd9Sstevel@tonic-gate 93*7c478bd9Sstevel@tonic-gate tstate[0].cs_next = &tstate[max_state]; 94*7c478bd9Sstevel@tonic-gate tstate[0].cs_id = 0; 95*7c478bd9Sstevel@tonic-gate 96*7c478bd9Sstevel@tonic-gate comp->last_cs = &tstate[0]; 97*7c478bd9Sstevel@tonic-gate comp->last_recv = 255; 98*7c478bd9Sstevel@tonic-gate comp->last_xmit = 255; 99*7c478bd9Sstevel@tonic-gate comp->flags = VJF_TOSS; 100*7c478bd9Sstevel@tonic-gate } 101*7c478bd9Sstevel@tonic-gate 102*7c478bd9Sstevel@tonic-gate /* 103*7c478bd9Sstevel@tonic-gate * ENCODE encodes a number that is known to be non-zero. ENCODEZ 104*7c478bd9Sstevel@tonic-gate * checks for zero (since zero has to be encoded in the long, 3 byte 105*7c478bd9Sstevel@tonic-gate * form). 106*7c478bd9Sstevel@tonic-gate */ 107*7c478bd9Sstevel@tonic-gate #define ENCODE(n) { \ 108*7c478bd9Sstevel@tonic-gate if ((ushort_t)(n) >= 256) { \ 109*7c478bd9Sstevel@tonic-gate *cp++ = 0; \ 110*7c478bd9Sstevel@tonic-gate cp[1] = (n) & 0xff; \ 111*7c478bd9Sstevel@tonic-gate cp[0] = ((n) >> 8) & 0xff; \ 112*7c478bd9Sstevel@tonic-gate cp += 2; \ 113*7c478bd9Sstevel@tonic-gate } else { \ 114*7c478bd9Sstevel@tonic-gate *cp++ = (n) & 0xff; \ 115*7c478bd9Sstevel@tonic-gate } \ 116*7c478bd9Sstevel@tonic-gate } 117*7c478bd9Sstevel@tonic-gate #define ENCODEZ(n) { \ 118*7c478bd9Sstevel@tonic-gate if ((ushort_t)(n) >= 256 || (ushort_t)(n) == 0) { \ 119*7c478bd9Sstevel@tonic-gate *cp++ = 0; \ 120*7c478bd9Sstevel@tonic-gate cp[1] = (n) & 0xff; \ 121*7c478bd9Sstevel@tonic-gate cp[0] = ((n) >> 8) & 0xff; \ 122*7c478bd9Sstevel@tonic-gate cp += 2; \ 123*7c478bd9Sstevel@tonic-gate } else { \ 124*7c478bd9Sstevel@tonic-gate *cp++ = (n) & 0xff; \ 125*7c478bd9Sstevel@tonic-gate } \ 126*7c478bd9Sstevel@tonic-gate } 127*7c478bd9Sstevel@tonic-gate 128*7c478bd9Sstevel@tonic-gate #define DECODEL(f) { \ 129*7c478bd9Sstevel@tonic-gate if (*cp == 0) { \ 130*7c478bd9Sstevel@tonic-gate uint32_t tmp = ntohl(f) + ((cp[1] << 8) | cp[2]); \ 131*7c478bd9Sstevel@tonic-gate (f) = htonl(tmp); \ 132*7c478bd9Sstevel@tonic-gate cp += 3; \ 133*7c478bd9Sstevel@tonic-gate } else { \ 134*7c478bd9Sstevel@tonic-gate uint32_t tmp = ntohl(f) + (uint32_t)*cp++; \ 135*7c478bd9Sstevel@tonic-gate (f) = htonl(tmp); \ 136*7c478bd9Sstevel@tonic-gate } \ 137*7c478bd9Sstevel@tonic-gate } 138*7c478bd9Sstevel@tonic-gate 139*7c478bd9Sstevel@tonic-gate #define DECODES(f) { \ 140*7c478bd9Sstevel@tonic-gate if (*cp == 0) { \ 141*7c478bd9Sstevel@tonic-gate ushort_t tmp = ntohs(f) + ((cp[1] << 8) | cp[2]); \ 142*7c478bd9Sstevel@tonic-gate (f) = htons(tmp); \ 143*7c478bd9Sstevel@tonic-gate cp += 3; \ 144*7c478bd9Sstevel@tonic-gate } else { \ 145*7c478bd9Sstevel@tonic-gate ushort_t tmp = ntohs(f) + (uint32_t)*cp++; \ 146*7c478bd9Sstevel@tonic-gate (f) = htons(tmp); \ 147*7c478bd9Sstevel@tonic-gate } \ 148*7c478bd9Sstevel@tonic-gate } 149*7c478bd9Sstevel@tonic-gate 150*7c478bd9Sstevel@tonic-gate #define DECODEU(f) { \ 151*7c478bd9Sstevel@tonic-gate if (*cp == 0) { \ 152*7c478bd9Sstevel@tonic-gate (f) = htons((cp[1] << 8) | cp[2]); \ 153*7c478bd9Sstevel@tonic-gate cp += 3; \ 154*7c478bd9Sstevel@tonic-gate } else { \ 155*7c478bd9Sstevel@tonic-gate (f) = htons((uint32_t)*cp++); \ 156*7c478bd9Sstevel@tonic-gate } \ 157*7c478bd9Sstevel@tonic-gate } 158*7c478bd9Sstevel@tonic-gate 159*7c478bd9Sstevel@tonic-gate uint_t 160*7c478bd9Sstevel@tonic-gate vj_compress_tcp(register struct ip *ip, uint_t mlen, struct vjcompress *comp, 161*7c478bd9Sstevel@tonic-gate int compress_cid, uchar_t **vjhdrp) 162*7c478bd9Sstevel@tonic-gate { 163*7c478bd9Sstevel@tonic-gate register struct cstate *cs = comp->last_cs->cs_next; 164*7c478bd9Sstevel@tonic-gate register uint_t hlen = getip_hl(ip); 165*7c478bd9Sstevel@tonic-gate register struct tcphdr *oth; 166*7c478bd9Sstevel@tonic-gate register struct tcphdr *th; 167*7c478bd9Sstevel@tonic-gate register uint_t deltaS; 168*7c478bd9Sstevel@tonic-gate register uint_t deltaA; 169*7c478bd9Sstevel@tonic-gate register uint_t changes = 0; 170*7c478bd9Sstevel@tonic-gate uchar_t new_seq[16]; 171*7c478bd9Sstevel@tonic-gate register uchar_t *cp = new_seq; 172*7c478bd9Sstevel@tonic-gate register uint_t thlen; 173*7c478bd9Sstevel@tonic-gate 174*7c478bd9Sstevel@tonic-gate /* 175*7c478bd9Sstevel@tonic-gate * Bail if this is an IP fragment or if the TCP packet isn't 176*7c478bd9Sstevel@tonic-gate * `compressible' (i.e., ACK isn't set or some other control bit is 177*7c478bd9Sstevel@tonic-gate * set). (We assume that the caller has already made sure the 178*7c478bd9Sstevel@tonic-gate * packet is IP proto TCP) 179*7c478bd9Sstevel@tonic-gate */ 180*7c478bd9Sstevel@tonic-gate if ((ip->ip_off & htons(0x3fff)) || mlen < 40) { 181*7c478bd9Sstevel@tonic-gate return (TYPE_IP); 182*7c478bd9Sstevel@tonic-gate } 183*7c478bd9Sstevel@tonic-gate 184*7c478bd9Sstevel@tonic-gate th = (struct tcphdr *)&((int *)ip)[hlen]; 185*7c478bd9Sstevel@tonic-gate 186*7c478bd9Sstevel@tonic-gate if ((th->th_flags & (TH_SYN|TH_FIN|TH_RST|TH_ACK)) != TH_ACK) { 187*7c478bd9Sstevel@tonic-gate return (TYPE_IP); 188*7c478bd9Sstevel@tonic-gate } 189*7c478bd9Sstevel@tonic-gate 190*7c478bd9Sstevel@tonic-gate thlen = (hlen + getth_off(th)) << 2; 191*7c478bd9Sstevel@tonic-gate if (thlen > mlen) { 192*7c478bd9Sstevel@tonic-gate return (TYPE_IP); 193*7c478bd9Sstevel@tonic-gate } 194*7c478bd9Sstevel@tonic-gate 195*7c478bd9Sstevel@tonic-gate /* 196*7c478bd9Sstevel@tonic-gate * Packet is compressible -- we're going to send either a 197*7c478bd9Sstevel@tonic-gate * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way we need 198*7c478bd9Sstevel@tonic-gate * to locate (or create) the connection state. Special case the 199*7c478bd9Sstevel@tonic-gate * most recently used connection since it's most likely to be used 200*7c478bd9Sstevel@tonic-gate * again & we don't have to do any reordering if it's used. 201*7c478bd9Sstevel@tonic-gate */ 202*7c478bd9Sstevel@tonic-gate INCR(vjs_packets); 203*7c478bd9Sstevel@tonic-gate 204*7c478bd9Sstevel@tonic-gate if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr || 205*7c478bd9Sstevel@tonic-gate ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr || 206*7c478bd9Sstevel@tonic-gate *(int *)th != ((int *)&cs->cs_ip)[getip_hl(&cs->cs_ip)]) { 207*7c478bd9Sstevel@tonic-gate 208*7c478bd9Sstevel@tonic-gate /* 209*7c478bd9Sstevel@tonic-gate * Wasn't the first -- search for it. 210*7c478bd9Sstevel@tonic-gate * 211*7c478bd9Sstevel@tonic-gate * States are kept in a circularly linked list with 212*7c478bd9Sstevel@tonic-gate * last_cs pointing to the end of the list. The 213*7c478bd9Sstevel@tonic-gate * list is kept in lru order by moving a state to the 214*7c478bd9Sstevel@tonic-gate * head of the list whenever it is referenced. Since 215*7c478bd9Sstevel@tonic-gate * the list is short and, empirically, the connection 216*7c478bd9Sstevel@tonic-gate * we want is almost always near the front, we locate 217*7c478bd9Sstevel@tonic-gate * states via linear search. If we don't find a state 218*7c478bd9Sstevel@tonic-gate * for the datagram, the oldest state is (re-)used. 219*7c478bd9Sstevel@tonic-gate */ 220*7c478bd9Sstevel@tonic-gate register struct cstate *lcs; 221*7c478bd9Sstevel@tonic-gate register struct cstate *lastcs = comp->last_cs; 222*7c478bd9Sstevel@tonic-gate 223*7c478bd9Sstevel@tonic-gate do { 224*7c478bd9Sstevel@tonic-gate lcs = cs; cs = cs->cs_next; 225*7c478bd9Sstevel@tonic-gate 226*7c478bd9Sstevel@tonic-gate INCR(vjs_searches); 227*7c478bd9Sstevel@tonic-gate 228*7c478bd9Sstevel@tonic-gate if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr && 229*7c478bd9Sstevel@tonic-gate ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr && 230*7c478bd9Sstevel@tonic-gate *(int *)th == ((int *) 231*7c478bd9Sstevel@tonic-gate &cs->cs_ip)[getip_hl(&cs->cs_ip)]) { 232*7c478bd9Sstevel@tonic-gate 233*7c478bd9Sstevel@tonic-gate goto found; 234*7c478bd9Sstevel@tonic-gate } 235*7c478bd9Sstevel@tonic-gate 236*7c478bd9Sstevel@tonic-gate } while (cs != lastcs); 237*7c478bd9Sstevel@tonic-gate 238*7c478bd9Sstevel@tonic-gate /* 239*7c478bd9Sstevel@tonic-gate * Didn't find it -- re-use oldest cstate. Send an 240*7c478bd9Sstevel@tonic-gate * uncompressed packet that tells the other side what 241*7c478bd9Sstevel@tonic-gate * connection number we're using for this conversation. 242*7c478bd9Sstevel@tonic-gate * Note that since the state list is circular, the oldest 243*7c478bd9Sstevel@tonic-gate * state points to the newest and we only need to set 244*7c478bd9Sstevel@tonic-gate * last_cs to update the lru linkage. 245*7c478bd9Sstevel@tonic-gate */ 246*7c478bd9Sstevel@tonic-gate INCR(vjs_misses); 247*7c478bd9Sstevel@tonic-gate 248*7c478bd9Sstevel@tonic-gate comp->last_cs = lcs; 249*7c478bd9Sstevel@tonic-gate 250*7c478bd9Sstevel@tonic-gate goto uncompressed; 251*7c478bd9Sstevel@tonic-gate 252*7c478bd9Sstevel@tonic-gate found: 253*7c478bd9Sstevel@tonic-gate /* 254*7c478bd9Sstevel@tonic-gate * Found it -- move to the front on the connection list. 255*7c478bd9Sstevel@tonic-gate */ 256*7c478bd9Sstevel@tonic-gate if (cs == lastcs) { 257*7c478bd9Sstevel@tonic-gate comp->last_cs = lcs; 258*7c478bd9Sstevel@tonic-gate } else { 259*7c478bd9Sstevel@tonic-gate lcs->cs_next = cs->cs_next; 260*7c478bd9Sstevel@tonic-gate cs->cs_next = lastcs->cs_next; 261*7c478bd9Sstevel@tonic-gate lastcs->cs_next = cs; 262*7c478bd9Sstevel@tonic-gate } 263*7c478bd9Sstevel@tonic-gate } 264*7c478bd9Sstevel@tonic-gate 265*7c478bd9Sstevel@tonic-gate /* 266*7c478bd9Sstevel@tonic-gate * Make sure that only what we expect to change changed. The first 267*7c478bd9Sstevel@tonic-gate * line of the `if' checks the IP protocol version, header length & 268*7c478bd9Sstevel@tonic-gate * type of service. The 2nd line checks the "Don't fragment" bit. 269*7c478bd9Sstevel@tonic-gate * The 3rd line checks the time-to-live and protocol (the protocol 270*7c478bd9Sstevel@tonic-gate * check is unnecessary but costless). The 4th line checks the TCP 271*7c478bd9Sstevel@tonic-gate * header length. The 5th line checks IP options, if any. The 6th 272*7c478bd9Sstevel@tonic-gate * line checks TCP options, if any. If any of these things are 273*7c478bd9Sstevel@tonic-gate * different between the previous & current datagram, we send the 274*7c478bd9Sstevel@tonic-gate * current datagram `uncompressed'. 275*7c478bd9Sstevel@tonic-gate */ 276*7c478bd9Sstevel@tonic-gate oth = (struct tcphdr *)&((int *)&cs->cs_ip)[hlen]; 277*7c478bd9Sstevel@tonic-gate 278*7c478bd9Sstevel@tonic-gate /* Used to check for IP options. */ 279*7c478bd9Sstevel@tonic-gate deltaS = hlen; 280*7c478bd9Sstevel@tonic-gate 281*7c478bd9Sstevel@tonic-gate if (((ushort_t *)ip)[0] != ((ushort_t *)&cs->cs_ip)[0] || 282*7c478bd9Sstevel@tonic-gate ((ushort_t *)ip)[3] != ((ushort_t *)&cs->cs_ip)[3] || 283*7c478bd9Sstevel@tonic-gate ((ushort_t *)ip)[4] != ((ushort_t *)&cs->cs_ip)[4] || 284*7c478bd9Sstevel@tonic-gate getth_off(th) != getth_off(oth) || 285*7c478bd9Sstevel@tonic-gate (deltaS > 5 && 286*7c478bd9Sstevel@tonic-gate BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) || 287*7c478bd9Sstevel@tonic-gate (getth_off(th) > 5 && 288*7c478bd9Sstevel@tonic-gate BCMP(th + 1, oth + 1, (getth_off(th) - 5) << 2))) { 289*7c478bd9Sstevel@tonic-gate 290*7c478bd9Sstevel@tonic-gate goto uncompressed; 291*7c478bd9Sstevel@tonic-gate } 292*7c478bd9Sstevel@tonic-gate 293*7c478bd9Sstevel@tonic-gate /* 294*7c478bd9Sstevel@tonic-gate * Figure out which of the changing fields changed. The 295*7c478bd9Sstevel@tonic-gate * receiver expects changes in the order: urgent, window, 296*7c478bd9Sstevel@tonic-gate * ack, seq (the order minimizes the number of temporaries 297*7c478bd9Sstevel@tonic-gate * needed in this section of code). 298*7c478bd9Sstevel@tonic-gate */ 299*7c478bd9Sstevel@tonic-gate if (th->th_flags & TH_URG) { 300*7c478bd9Sstevel@tonic-gate 301*7c478bd9Sstevel@tonic-gate deltaS = ntohs(th->th_urp); 302*7c478bd9Sstevel@tonic-gate 303*7c478bd9Sstevel@tonic-gate ENCODEZ(deltaS); 304*7c478bd9Sstevel@tonic-gate 305*7c478bd9Sstevel@tonic-gate changes |= NEW_U; 306*7c478bd9Sstevel@tonic-gate 307*7c478bd9Sstevel@tonic-gate } else if (th->th_urp != oth->th_urp) { 308*7c478bd9Sstevel@tonic-gate 309*7c478bd9Sstevel@tonic-gate /* 310*7c478bd9Sstevel@tonic-gate * argh! URG not set but urp changed -- a sensible 311*7c478bd9Sstevel@tonic-gate * implementation should never do this but RFC793 312*7c478bd9Sstevel@tonic-gate * doesn't prohibit the change so we have to deal 313*7c478bd9Sstevel@tonic-gate * with it 314*7c478bd9Sstevel@tonic-gate */ 315*7c478bd9Sstevel@tonic-gate goto uncompressed; 316*7c478bd9Sstevel@tonic-gate } 317*7c478bd9Sstevel@tonic-gate 318*7c478bd9Sstevel@tonic-gate if ((deltaS = (ushort_t)(ntohs(th->th_win) - ntohs(oth->th_win))) > 0) { 319*7c478bd9Sstevel@tonic-gate ENCODE(deltaS); 320*7c478bd9Sstevel@tonic-gate 321*7c478bd9Sstevel@tonic-gate changes |= NEW_W; 322*7c478bd9Sstevel@tonic-gate } 323*7c478bd9Sstevel@tonic-gate 324*7c478bd9Sstevel@tonic-gate if ((deltaA = ntohl(th->th_ack) - ntohl(oth->th_ack)) > 0) { 325*7c478bd9Sstevel@tonic-gate if (deltaA > 0xffff) { 326*7c478bd9Sstevel@tonic-gate goto uncompressed; 327*7c478bd9Sstevel@tonic-gate } 328*7c478bd9Sstevel@tonic-gate 329*7c478bd9Sstevel@tonic-gate ENCODE(deltaA); 330*7c478bd9Sstevel@tonic-gate 331*7c478bd9Sstevel@tonic-gate changes |= NEW_A; 332*7c478bd9Sstevel@tonic-gate } 333*7c478bd9Sstevel@tonic-gate 334*7c478bd9Sstevel@tonic-gate if ((deltaS = ntohl(th->th_seq) - ntohl(oth->th_seq)) > 0) { 335*7c478bd9Sstevel@tonic-gate if (deltaS > 0xffff) { 336*7c478bd9Sstevel@tonic-gate goto uncompressed; 337*7c478bd9Sstevel@tonic-gate } 338*7c478bd9Sstevel@tonic-gate 339*7c478bd9Sstevel@tonic-gate ENCODE(deltaS); 340*7c478bd9Sstevel@tonic-gate 341*7c478bd9Sstevel@tonic-gate changes |= NEW_S; 342*7c478bd9Sstevel@tonic-gate } 343*7c478bd9Sstevel@tonic-gate 344*7c478bd9Sstevel@tonic-gate switch (changes) { 345*7c478bd9Sstevel@tonic-gate 346*7c478bd9Sstevel@tonic-gate case 0: 347*7c478bd9Sstevel@tonic-gate /* 348*7c478bd9Sstevel@tonic-gate * Nothing changed. If this packet contains data and the 349*7c478bd9Sstevel@tonic-gate * last one didn't, this is probably a data packet following 350*7c478bd9Sstevel@tonic-gate * an ack (normal on an interactive connection) and we send 351*7c478bd9Sstevel@tonic-gate * it compressed. Otherwise it's probably a retransmit, 352*7c478bd9Sstevel@tonic-gate * retransmitted ack or window probe. Send it uncompressed 353*7c478bd9Sstevel@tonic-gate * in case the other side missed the compressed version. 354*7c478bd9Sstevel@tonic-gate */ 355*7c478bd9Sstevel@tonic-gate if (ip->ip_len != cs->cs_ip.ip_len && 356*7c478bd9Sstevel@tonic-gate ntohs(cs->cs_ip.ip_len) == thlen) { 357*7c478bd9Sstevel@tonic-gate break; 358*7c478bd9Sstevel@tonic-gate } 359*7c478bd9Sstevel@tonic-gate 360*7c478bd9Sstevel@tonic-gate /* (otherwise fall through) */ 361*7c478bd9Sstevel@tonic-gate /* FALLTHRU */ 362*7c478bd9Sstevel@tonic-gate 363*7c478bd9Sstevel@tonic-gate case SPECIAL_I: 364*7c478bd9Sstevel@tonic-gate case SPECIAL_D: 365*7c478bd9Sstevel@tonic-gate 366*7c478bd9Sstevel@tonic-gate /* 367*7c478bd9Sstevel@tonic-gate * actual changes match one of our special case encodings -- 368*7c478bd9Sstevel@tonic-gate * send packet uncompressed. 369*7c478bd9Sstevel@tonic-gate */ 370*7c478bd9Sstevel@tonic-gate goto uncompressed; 371*7c478bd9Sstevel@tonic-gate 372*7c478bd9Sstevel@tonic-gate case NEW_S|NEW_A: 373*7c478bd9Sstevel@tonic-gate 374*7c478bd9Sstevel@tonic-gate if (deltaS == deltaA && 375*7c478bd9Sstevel@tonic-gate deltaS == ntohs(cs->cs_ip.ip_len) - thlen) { 376*7c478bd9Sstevel@tonic-gate 377*7c478bd9Sstevel@tonic-gate /* 378*7c478bd9Sstevel@tonic-gate * special case for echoed terminal traffic 379*7c478bd9Sstevel@tonic-gate */ 380*7c478bd9Sstevel@tonic-gate changes = SPECIAL_I; 381*7c478bd9Sstevel@tonic-gate cp = new_seq; 382*7c478bd9Sstevel@tonic-gate } 383*7c478bd9Sstevel@tonic-gate 384*7c478bd9Sstevel@tonic-gate break; 385*7c478bd9Sstevel@tonic-gate 386*7c478bd9Sstevel@tonic-gate case NEW_S: 387*7c478bd9Sstevel@tonic-gate 388*7c478bd9Sstevel@tonic-gate if (deltaS == ntohs(cs->cs_ip.ip_len) - thlen) { 389*7c478bd9Sstevel@tonic-gate 390*7c478bd9Sstevel@tonic-gate /* 391*7c478bd9Sstevel@tonic-gate * special case for data xfer 392*7c478bd9Sstevel@tonic-gate */ 393*7c478bd9Sstevel@tonic-gate changes = SPECIAL_D; 394*7c478bd9Sstevel@tonic-gate cp = new_seq; 395*7c478bd9Sstevel@tonic-gate } 396*7c478bd9Sstevel@tonic-gate 397*7c478bd9Sstevel@tonic-gate break; 398*7c478bd9Sstevel@tonic-gate } 399*7c478bd9Sstevel@tonic-gate 400*7c478bd9Sstevel@tonic-gate deltaS = ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id); 401*7c478bd9Sstevel@tonic-gate if (deltaS != 1) { 402*7c478bd9Sstevel@tonic-gate ENCODEZ(deltaS); 403*7c478bd9Sstevel@tonic-gate 404*7c478bd9Sstevel@tonic-gate changes |= NEW_I; 405*7c478bd9Sstevel@tonic-gate } 406*7c478bd9Sstevel@tonic-gate 407*7c478bd9Sstevel@tonic-gate if (th->th_flags & TH_PUSH) { 408*7c478bd9Sstevel@tonic-gate changes |= TCP_PUSH_BIT; 409*7c478bd9Sstevel@tonic-gate } 410*7c478bd9Sstevel@tonic-gate 411*7c478bd9Sstevel@tonic-gate /* 412*7c478bd9Sstevel@tonic-gate * Grab the cksum before we overwrite it below. Then update our 413*7c478bd9Sstevel@tonic-gate * state with this packet's header. 414*7c478bd9Sstevel@tonic-gate */ 415*7c478bd9Sstevel@tonic-gate deltaA = ntohs(th->th_sum); 416*7c478bd9Sstevel@tonic-gate 417*7c478bd9Sstevel@tonic-gate BCOPY(ip, &cs->cs_ip, thlen); 418*7c478bd9Sstevel@tonic-gate 419*7c478bd9Sstevel@tonic-gate /* 420*7c478bd9Sstevel@tonic-gate * We want to use the original packet as our compressed packet. 421*7c478bd9Sstevel@tonic-gate * (cp - new_seq) is the number of bytes we need for compressed 422*7c478bd9Sstevel@tonic-gate * sequence numbers. In addition we need one byte for the change 423*7c478bd9Sstevel@tonic-gate * mask, one for the connection id and two for the tcp checksum. 424*7c478bd9Sstevel@tonic-gate * So, (cp - new_seq) + 4 bytes of header are needed. thlen is how 425*7c478bd9Sstevel@tonic-gate * many bytes of the original packet to toss so subtract the two to 426*7c478bd9Sstevel@tonic-gate * get the new packet size. 427*7c478bd9Sstevel@tonic-gate */ 428*7c478bd9Sstevel@tonic-gate deltaS = cp - new_seq; 429*7c478bd9Sstevel@tonic-gate 430*7c478bd9Sstevel@tonic-gate cp = (uchar_t *)ip; 431*7c478bd9Sstevel@tonic-gate 432*7c478bd9Sstevel@tonic-gate if (compress_cid == 0 || comp->last_xmit != cs->cs_id) { 433*7c478bd9Sstevel@tonic-gate comp->last_xmit = cs->cs_id; 434*7c478bd9Sstevel@tonic-gate 435*7c478bd9Sstevel@tonic-gate thlen -= deltaS + 4; 436*7c478bd9Sstevel@tonic-gate 437*7c478bd9Sstevel@tonic-gate *vjhdrp = (cp += thlen); 438*7c478bd9Sstevel@tonic-gate 439*7c478bd9Sstevel@tonic-gate *cp++ = changes | NEW_C; 440*7c478bd9Sstevel@tonic-gate *cp++ = cs->cs_id; 441*7c478bd9Sstevel@tonic-gate } else { 442*7c478bd9Sstevel@tonic-gate thlen -= deltaS + 3; 443*7c478bd9Sstevel@tonic-gate 444*7c478bd9Sstevel@tonic-gate *vjhdrp = (cp += thlen); 445*7c478bd9Sstevel@tonic-gate 446*7c478bd9Sstevel@tonic-gate *cp++ = changes & 0xff; 447*7c478bd9Sstevel@tonic-gate } 448*7c478bd9Sstevel@tonic-gate 449*7c478bd9Sstevel@tonic-gate *cp++ = (deltaA >> 8) & 0xff; 450*7c478bd9Sstevel@tonic-gate *cp++ = deltaA & 0xff; 451*7c478bd9Sstevel@tonic-gate 452*7c478bd9Sstevel@tonic-gate BCOPY(new_seq, cp, deltaS); 453*7c478bd9Sstevel@tonic-gate 454*7c478bd9Sstevel@tonic-gate INCR(vjs_compressed); 455*7c478bd9Sstevel@tonic-gate 456*7c478bd9Sstevel@tonic-gate return (TYPE_COMPRESSED_TCP); 457*7c478bd9Sstevel@tonic-gate 458*7c478bd9Sstevel@tonic-gate /* 459*7c478bd9Sstevel@tonic-gate * Update connection state cs & send uncompressed packet (that is, 460*7c478bd9Sstevel@tonic-gate * a regular ip/tcp packet but with the 'conversation id' we hope 461*7c478bd9Sstevel@tonic-gate * to use on future compressed packets in the protocol field). 462*7c478bd9Sstevel@tonic-gate */ 463*7c478bd9Sstevel@tonic-gate uncompressed: 464*7c478bd9Sstevel@tonic-gate 465*7c478bd9Sstevel@tonic-gate BCOPY(ip, &cs->cs_ip, thlen); 466*7c478bd9Sstevel@tonic-gate 467*7c478bd9Sstevel@tonic-gate ip->ip_p = cs->cs_id; 468*7c478bd9Sstevel@tonic-gate comp->last_xmit = cs->cs_id; 469*7c478bd9Sstevel@tonic-gate 470*7c478bd9Sstevel@tonic-gate return (TYPE_UNCOMPRESSED_TCP); 471*7c478bd9Sstevel@tonic-gate } 472*7c478bd9Sstevel@tonic-gate 473*7c478bd9Sstevel@tonic-gate /* 474*7c478bd9Sstevel@tonic-gate * vj_uncompress_err() 475*7c478bd9Sstevel@tonic-gate * 476*7c478bd9Sstevel@tonic-gate * Called when we may have missed a packet. 477*7c478bd9Sstevel@tonic-gate */ 478*7c478bd9Sstevel@tonic-gate void 479*7c478bd9Sstevel@tonic-gate vj_uncompress_err(struct vjcompress *comp) 480*7c478bd9Sstevel@tonic-gate { 481*7c478bd9Sstevel@tonic-gate comp->flags |= VJF_TOSS; 482*7c478bd9Sstevel@tonic-gate 483*7c478bd9Sstevel@tonic-gate INCR(vjs_errorin); 484*7c478bd9Sstevel@tonic-gate } 485*7c478bd9Sstevel@tonic-gate 486*7c478bd9Sstevel@tonic-gate /* 487*7c478bd9Sstevel@tonic-gate * vj_uncompress_uncomp() 488*7c478bd9Sstevel@tonic-gate * 489*7c478bd9Sstevel@tonic-gate * "Uncompress" a packet of type TYPE_UNCOMPRESSED_TCP. 490*7c478bd9Sstevel@tonic-gate */ 491*7c478bd9Sstevel@tonic-gate int 492*7c478bd9Sstevel@tonic-gate vj_uncompress_uncomp(uchar_t *buf, int buflen, struct vjcompress *comp) 493*7c478bd9Sstevel@tonic-gate { 494*7c478bd9Sstevel@tonic-gate register uint_t hlen; 495*7c478bd9Sstevel@tonic-gate register struct cstate *cs; 496*7c478bd9Sstevel@tonic-gate 497*7c478bd9Sstevel@tonic-gate hlen = getip_hl(buf) << 2; 498*7c478bd9Sstevel@tonic-gate 499*7c478bd9Sstevel@tonic-gate if (getip_p(buf) >= MAX_STATES || 500*7c478bd9Sstevel@tonic-gate hlen + sizeof (struct tcphdr) > buflen || 501*7c478bd9Sstevel@tonic-gate (hlen += getth_off(buf+hlen) << 2) > buflen || hlen > MAX_HDR) { 502*7c478bd9Sstevel@tonic-gate 503*7c478bd9Sstevel@tonic-gate comp->flags |= VJF_TOSS; 504*7c478bd9Sstevel@tonic-gate 505*7c478bd9Sstevel@tonic-gate INCR(vjs_errorin); 506*7c478bd9Sstevel@tonic-gate 507*7c478bd9Sstevel@tonic-gate return (0); 508*7c478bd9Sstevel@tonic-gate } 509*7c478bd9Sstevel@tonic-gate 510*7c478bd9Sstevel@tonic-gate cs = &comp->rstate[comp->last_recv = getip_p(buf)]; 511*7c478bd9Sstevel@tonic-gate comp->flags &= ~VJF_TOSS; 512*7c478bd9Sstevel@tonic-gate setip_p(buf, IPPROTO_TCP); 513*7c478bd9Sstevel@tonic-gate 514*7c478bd9Sstevel@tonic-gate BCOPY(buf, &cs->cs_ip, hlen); 515*7c478bd9Sstevel@tonic-gate 516*7c478bd9Sstevel@tonic-gate cs->cs_hlen = hlen & 0xff; 517*7c478bd9Sstevel@tonic-gate 518*7c478bd9Sstevel@tonic-gate INCR(vjs_uncompressedin); 519*7c478bd9Sstevel@tonic-gate 520*7c478bd9Sstevel@tonic-gate return (1); 521*7c478bd9Sstevel@tonic-gate } 522*7c478bd9Sstevel@tonic-gate 523*7c478bd9Sstevel@tonic-gate /* 524*7c478bd9Sstevel@tonic-gate * vj_uncompress_tcp() 525*7c478bd9Sstevel@tonic-gate * 526*7c478bd9Sstevel@tonic-gate * Uncompress a packet of type TYPE_COMPRESSED_TCP. 527*7c478bd9Sstevel@tonic-gate * The packet starts at buf and is of total length total_len. 528*7c478bd9Sstevel@tonic-gate * The first buflen bytes are at buf; this must include the entire 529*7c478bd9Sstevel@tonic-gate * compressed TCP/IP header. This procedure returns the length 530*7c478bd9Sstevel@tonic-gate * of the VJ header, with a pointer to the uncompressed IP header 531*7c478bd9Sstevel@tonic-gate * in *hdrp and its length in *hlenp. 532*7c478bd9Sstevel@tonic-gate */ 533*7c478bd9Sstevel@tonic-gate int 534*7c478bd9Sstevel@tonic-gate vj_uncompress_tcp(uchar_t *buf, int buflen, int total_len, 535*7c478bd9Sstevel@tonic-gate struct vjcompress *comp, uchar_t **hdrp, uint_t *hlenp) 536*7c478bd9Sstevel@tonic-gate { 537*7c478bd9Sstevel@tonic-gate register uchar_t *cp; 538*7c478bd9Sstevel@tonic-gate register uint_t hlen; 539*7c478bd9Sstevel@tonic-gate register uint_t changes; 540*7c478bd9Sstevel@tonic-gate register struct tcphdr *th; 541*7c478bd9Sstevel@tonic-gate register struct cstate *cs; 542*7c478bd9Sstevel@tonic-gate register ushort_t *bp; 543*7c478bd9Sstevel@tonic-gate register uint_t vjlen; 544*7c478bd9Sstevel@tonic-gate register uint32_t tmp; 545*7c478bd9Sstevel@tonic-gate 546*7c478bd9Sstevel@tonic-gate INCR(vjs_compressedin); 547*7c478bd9Sstevel@tonic-gate 548*7c478bd9Sstevel@tonic-gate cp = buf; 549*7c478bd9Sstevel@tonic-gate changes = *cp++; 550*7c478bd9Sstevel@tonic-gate 551*7c478bd9Sstevel@tonic-gate if (changes & NEW_C) { 552*7c478bd9Sstevel@tonic-gate /* 553*7c478bd9Sstevel@tonic-gate * Make sure the state index is in range, then grab the state. 554*7c478bd9Sstevel@tonic-gate * If we have a good state index, clear the 'discard' flag. 555*7c478bd9Sstevel@tonic-gate */ 556*7c478bd9Sstevel@tonic-gate if (*cp >= MAX_STATES) { 557*7c478bd9Sstevel@tonic-gate goto bad; 558*7c478bd9Sstevel@tonic-gate } 559*7c478bd9Sstevel@tonic-gate 560*7c478bd9Sstevel@tonic-gate comp->flags &= ~VJF_TOSS; 561*7c478bd9Sstevel@tonic-gate comp->last_recv = *cp++; 562*7c478bd9Sstevel@tonic-gate } else { 563*7c478bd9Sstevel@tonic-gate /* 564*7c478bd9Sstevel@tonic-gate * this packet has an implicit state index. If we've 565*7c478bd9Sstevel@tonic-gate * had a line error since the last time we got an 566*7c478bd9Sstevel@tonic-gate * explicit state index, we have to toss the packet 567*7c478bd9Sstevel@tonic-gate */ 568*7c478bd9Sstevel@tonic-gate if (comp->flags & VJF_TOSS) { 569*7c478bd9Sstevel@tonic-gate INCR(vjs_tossed); 570*7c478bd9Sstevel@tonic-gate return (-1); 571*7c478bd9Sstevel@tonic-gate } 572*7c478bd9Sstevel@tonic-gate } 573*7c478bd9Sstevel@tonic-gate 574*7c478bd9Sstevel@tonic-gate cs = &comp->rstate[comp->last_recv]; 575*7c478bd9Sstevel@tonic-gate hlen = getip_hl(&cs->cs_ip) << 2; 576*7c478bd9Sstevel@tonic-gate 577*7c478bd9Sstevel@tonic-gate th = (struct tcphdr *)((uint32_t *)&cs->cs_ip+hlen/sizeof (uint32_t)); 578*7c478bd9Sstevel@tonic-gate th->th_sum = htons((*cp << 8) | cp[1]); 579*7c478bd9Sstevel@tonic-gate 580*7c478bd9Sstevel@tonic-gate cp += 2; 581*7c478bd9Sstevel@tonic-gate 582*7c478bd9Sstevel@tonic-gate if (changes & TCP_PUSH_BIT) { 583*7c478bd9Sstevel@tonic-gate th->th_flags |= TH_PUSH; 584*7c478bd9Sstevel@tonic-gate } else { 585*7c478bd9Sstevel@tonic-gate th->th_flags &= ~TH_PUSH; 586*7c478bd9Sstevel@tonic-gate } 587*7c478bd9Sstevel@tonic-gate 588*7c478bd9Sstevel@tonic-gate switch (changes & SPECIALS_MASK) { 589*7c478bd9Sstevel@tonic-gate 590*7c478bd9Sstevel@tonic-gate case SPECIAL_I: 591*7c478bd9Sstevel@tonic-gate 592*7c478bd9Sstevel@tonic-gate { 593*7c478bd9Sstevel@tonic-gate 594*7c478bd9Sstevel@tonic-gate register uint32_t i; 595*7c478bd9Sstevel@tonic-gate 596*7c478bd9Sstevel@tonic-gate i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen; 597*7c478bd9Sstevel@tonic-gate 598*7c478bd9Sstevel@tonic-gate tmp = ntohl(th->th_ack) + i; 599*7c478bd9Sstevel@tonic-gate th->th_ack = htonl(tmp); 600*7c478bd9Sstevel@tonic-gate 601*7c478bd9Sstevel@tonic-gate tmp = ntohl(th->th_seq) + i; 602*7c478bd9Sstevel@tonic-gate th->th_seq = htonl(tmp); 603*7c478bd9Sstevel@tonic-gate 604*7c478bd9Sstevel@tonic-gate } 605*7c478bd9Sstevel@tonic-gate 606*7c478bd9Sstevel@tonic-gate break; 607*7c478bd9Sstevel@tonic-gate 608*7c478bd9Sstevel@tonic-gate case SPECIAL_D: 609*7c478bd9Sstevel@tonic-gate 610*7c478bd9Sstevel@tonic-gate tmp = ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len) - cs->cs_hlen; 611*7c478bd9Sstevel@tonic-gate th->th_seq = htonl(tmp); 612*7c478bd9Sstevel@tonic-gate 613*7c478bd9Sstevel@tonic-gate break; 614*7c478bd9Sstevel@tonic-gate 615*7c478bd9Sstevel@tonic-gate default: 616*7c478bd9Sstevel@tonic-gate 617*7c478bd9Sstevel@tonic-gate if (changes & NEW_U) { 618*7c478bd9Sstevel@tonic-gate th->th_flags |= TH_URG; 619*7c478bd9Sstevel@tonic-gate DECODEU(th->th_urp); 620*7c478bd9Sstevel@tonic-gate } else { 621*7c478bd9Sstevel@tonic-gate th->th_flags &= ~TH_URG; 622*7c478bd9Sstevel@tonic-gate } 623*7c478bd9Sstevel@tonic-gate 624*7c478bd9Sstevel@tonic-gate if (changes & NEW_W) { 625*7c478bd9Sstevel@tonic-gate DECODES(th->th_win); 626*7c478bd9Sstevel@tonic-gate } 627*7c478bd9Sstevel@tonic-gate 628*7c478bd9Sstevel@tonic-gate if (changes & NEW_A) { 629*7c478bd9Sstevel@tonic-gate DECODEL(th->th_ack); 630*7c478bd9Sstevel@tonic-gate } 631*7c478bd9Sstevel@tonic-gate 632*7c478bd9Sstevel@tonic-gate if (changes & NEW_S) { 633*7c478bd9Sstevel@tonic-gate DECODEL(th->th_seq); 634*7c478bd9Sstevel@tonic-gate } 635*7c478bd9Sstevel@tonic-gate 636*7c478bd9Sstevel@tonic-gate break; 637*7c478bd9Sstevel@tonic-gate } 638*7c478bd9Sstevel@tonic-gate 639*7c478bd9Sstevel@tonic-gate if (changes & NEW_I) { 640*7c478bd9Sstevel@tonic-gate DECODES(cs->cs_ip.ip_id); 641*7c478bd9Sstevel@tonic-gate } else { 642*7c478bd9Sstevel@tonic-gate cs->cs_ip.ip_id = ntohs(cs->cs_ip.ip_id) + 1; 643*7c478bd9Sstevel@tonic-gate cs->cs_ip.ip_id = htons(cs->cs_ip.ip_id); 644*7c478bd9Sstevel@tonic-gate } 645*7c478bd9Sstevel@tonic-gate 646*7c478bd9Sstevel@tonic-gate /* 647*7c478bd9Sstevel@tonic-gate * At this point, cp points to the first byte of data in the 648*7c478bd9Sstevel@tonic-gate * packet. Fill in the IP total length and update the IP 649*7c478bd9Sstevel@tonic-gate * header checksum. 650*7c478bd9Sstevel@tonic-gate */ 651*7c478bd9Sstevel@tonic-gate vjlen = cp - buf; 652*7c478bd9Sstevel@tonic-gate buflen -= vjlen; 653*7c478bd9Sstevel@tonic-gate if (buflen < 0) { 654*7c478bd9Sstevel@tonic-gate /* 655*7c478bd9Sstevel@tonic-gate * we must have dropped some characters (crc should detect 656*7c478bd9Sstevel@tonic-gate * this but the old slip framing won't) 657*7c478bd9Sstevel@tonic-gate */ 658*7c478bd9Sstevel@tonic-gate goto bad; 659*7c478bd9Sstevel@tonic-gate } 660*7c478bd9Sstevel@tonic-gate 661*7c478bd9Sstevel@tonic-gate total_len += cs->cs_hlen - vjlen; 662*7c478bd9Sstevel@tonic-gate cs->cs_ip.ip_len = htons(total_len); 663*7c478bd9Sstevel@tonic-gate 664*7c478bd9Sstevel@tonic-gate /* 665*7c478bd9Sstevel@tonic-gate * recompute the ip header checksum 666*7c478bd9Sstevel@tonic-gate */ 667*7c478bd9Sstevel@tonic-gate bp = (ushort_t *)&cs->cs_ip; 668*7c478bd9Sstevel@tonic-gate cs->cs_ip.ip_sum = 0; 669*7c478bd9Sstevel@tonic-gate 670*7c478bd9Sstevel@tonic-gate for (changes = 0; hlen > 0; hlen -= 2) { 671*7c478bd9Sstevel@tonic-gate changes += *bp++; 672*7c478bd9Sstevel@tonic-gate } 673*7c478bd9Sstevel@tonic-gate 674*7c478bd9Sstevel@tonic-gate changes = (changes & 0xffff) + (changes >> 16); 675*7c478bd9Sstevel@tonic-gate changes = (changes & 0xffff) + (changes >> 16); 676*7c478bd9Sstevel@tonic-gate cs->cs_ip.ip_sum = ~ changes; 677*7c478bd9Sstevel@tonic-gate 678*7c478bd9Sstevel@tonic-gate *hdrp = (uchar_t *)&cs->cs_ip; 679*7c478bd9Sstevel@tonic-gate *hlenp = cs->cs_hlen; 680*7c478bd9Sstevel@tonic-gate 681*7c478bd9Sstevel@tonic-gate return (vjlen); 682*7c478bd9Sstevel@tonic-gate 683*7c478bd9Sstevel@tonic-gate bad: 684*7c478bd9Sstevel@tonic-gate 685*7c478bd9Sstevel@tonic-gate comp->flags |= VJF_TOSS; 686*7c478bd9Sstevel@tonic-gate 687*7c478bd9Sstevel@tonic-gate INCR(vjs_errorin); 688*7c478bd9Sstevel@tonic-gate 689*7c478bd9Sstevel@tonic-gate return (-1); 690*7c478bd9Sstevel@tonic-gate } 691