xref: /nrf52832-nimble/rt-thread/components/net/lwip-2.1.0/src/netif/ppp/vj.c (revision 104654410c56c573564690304ae786df310c91fc)
1*10465441SEvalZero /*
2*10465441SEvalZero  * Routines to compress and uncompess tcp packets (for transmission
3*10465441SEvalZero  * over low speed serial lines.
4*10465441SEvalZero  *
5*10465441SEvalZero  * Copyright (c) 1989 Regents of the University of California.
6*10465441SEvalZero  * All rights reserved.
7*10465441SEvalZero  *
8*10465441SEvalZero  * Redistribution and use in source and binary forms are permitted
9*10465441SEvalZero  * provided that the above copyright notice and this paragraph are
10*10465441SEvalZero  * duplicated in all such forms and that any documentation,
11*10465441SEvalZero  * advertising materials, and other materials related to such
12*10465441SEvalZero  * distribution and use acknowledge that the software was developed
13*10465441SEvalZero  * by the University of California, Berkeley.  The name of the
14*10465441SEvalZero  * University may not be used to endorse or promote products derived
15*10465441SEvalZero  * from this software without specific prior written permission.
16*10465441SEvalZero  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17*10465441SEvalZero  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18*10465441SEvalZero  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19*10465441SEvalZero  *
20*10465441SEvalZero  * Van Jacobson ([email protected]), Dec 31, 1989:
21*10465441SEvalZero  *   Initial distribution.
22*10465441SEvalZero  *
23*10465441SEvalZero  * Modified June 1993 by Paul Mackerras, [email protected],
24*10465441SEvalZero  * so that the entire packet being decompressed doesn't have
25*10465441SEvalZero  * to be in contiguous memory (just the compressed header).
26*10465441SEvalZero  *
27*10465441SEvalZero  * Modified March 1998 by Guy Lancaster, [email protected],
28*10465441SEvalZero  * for a 16 bit processor.
29*10465441SEvalZero  */
30*10465441SEvalZero 
31*10465441SEvalZero #include "netif/ppp/ppp_opts.h"
32*10465441SEvalZero #if PPP_SUPPORT && VJ_SUPPORT /* don't build if not configured for use in lwipopts.h */
33*10465441SEvalZero 
34*10465441SEvalZero #include "netif/ppp/ppp_impl.h"
35*10465441SEvalZero #include "netif/ppp/pppdebug.h"
36*10465441SEvalZero 
37*10465441SEvalZero #include "netif/ppp/vj.h"
38*10465441SEvalZero 
39*10465441SEvalZero #include <string.h>
40*10465441SEvalZero 
41*10465441SEvalZero #if LINK_STATS
42*10465441SEvalZero #define INCR(counter) ++comp->stats.counter
43*10465441SEvalZero #else
44*10465441SEvalZero #define INCR(counter)
45*10465441SEvalZero #endif
46*10465441SEvalZero 
47*10465441SEvalZero void
vj_compress_init(struct vjcompress * comp)48*10465441SEvalZero vj_compress_init(struct vjcompress *comp)
49*10465441SEvalZero {
50*10465441SEvalZero   u8_t i;
51*10465441SEvalZero   struct cstate *tstate = comp->tstate;
52*10465441SEvalZero 
53*10465441SEvalZero #if MAX_SLOTS == 0
54*10465441SEvalZero   memset((char *)comp, 0, sizeof(*comp));
55*10465441SEvalZero #endif
56*10465441SEvalZero   comp->maxSlotIndex = MAX_SLOTS - 1;
57*10465441SEvalZero   comp->compressSlot = 0;    /* Disable slot ID compression by default. */
58*10465441SEvalZero   for (i = MAX_SLOTS - 1; i > 0; --i) {
59*10465441SEvalZero     tstate[i].cs_id = i;
60*10465441SEvalZero     tstate[i].cs_next = &tstate[i - 1];
61*10465441SEvalZero   }
62*10465441SEvalZero   tstate[0].cs_next = &tstate[MAX_SLOTS - 1];
63*10465441SEvalZero   tstate[0].cs_id = 0;
64*10465441SEvalZero   comp->last_cs = &tstate[0];
65*10465441SEvalZero   comp->last_recv = 255;
66*10465441SEvalZero   comp->last_xmit = 255;
67*10465441SEvalZero   comp->flags = VJF_TOSS;
68*10465441SEvalZero }
69*10465441SEvalZero 
70*10465441SEvalZero 
71*10465441SEvalZero /* ENCODE encodes a number that is known to be non-zero.  ENCODEZ
72*10465441SEvalZero  * checks for zero (since zero has to be encoded in the long, 3 byte
73*10465441SEvalZero  * form).
74*10465441SEvalZero  */
75*10465441SEvalZero #define ENCODE(n) { \
76*10465441SEvalZero   if ((u16_t)(n) >= 256) { \
77*10465441SEvalZero     *cp++ = 0; \
78*10465441SEvalZero     cp[1] = (u8_t)(n); \
79*10465441SEvalZero     cp[0] = (u8_t)((n) >> 8); \
80*10465441SEvalZero     cp += 2; \
81*10465441SEvalZero   } else { \
82*10465441SEvalZero     *cp++ = (u8_t)(n); \
83*10465441SEvalZero   } \
84*10465441SEvalZero }
85*10465441SEvalZero #define ENCODEZ(n) { \
86*10465441SEvalZero   if ((u16_t)(n) >= 256 || (u16_t)(n) == 0) { \
87*10465441SEvalZero     *cp++ = 0; \
88*10465441SEvalZero     cp[1] = (u8_t)(n); \
89*10465441SEvalZero     cp[0] = (u8_t)((n) >> 8); \
90*10465441SEvalZero     cp += 2; \
91*10465441SEvalZero   } else { \
92*10465441SEvalZero     *cp++ = (u8_t)(n); \
93*10465441SEvalZero   } \
94*10465441SEvalZero }
95*10465441SEvalZero 
96*10465441SEvalZero #define DECODEL(f) { \
97*10465441SEvalZero   if (*cp == 0) {\
98*10465441SEvalZero     u32_t tmp_ = lwip_ntohl(f) + ((cp[1] << 8) | cp[2]); \
99*10465441SEvalZero     (f) = lwip_htonl(tmp_); \
100*10465441SEvalZero     cp += 3; \
101*10465441SEvalZero   } else { \
102*10465441SEvalZero     u32_t tmp_ = lwip_ntohl(f) + (u32_t)*cp++; \
103*10465441SEvalZero     (f) = lwip_htonl(tmp_); \
104*10465441SEvalZero   } \
105*10465441SEvalZero }
106*10465441SEvalZero 
107*10465441SEvalZero #define DECODES(f) { \
108*10465441SEvalZero   if (*cp == 0) {\
109*10465441SEvalZero     u16_t tmp_ = lwip_ntohs(f) + (((u16_t)cp[1] << 8) | cp[2]); \
110*10465441SEvalZero     (f) = lwip_htons(tmp_); \
111*10465441SEvalZero     cp += 3; \
112*10465441SEvalZero   } else { \
113*10465441SEvalZero     u16_t tmp_ = lwip_ntohs(f) + (u16_t)*cp++; \
114*10465441SEvalZero     (f) = lwip_htons(tmp_); \
115*10465441SEvalZero   } \
116*10465441SEvalZero }
117*10465441SEvalZero 
118*10465441SEvalZero #define DECODEU(f) { \
119*10465441SEvalZero   if (*cp == 0) {\
120*10465441SEvalZero     (f) = lwip_htons(((u16_t)cp[1] << 8) | cp[2]); \
121*10465441SEvalZero     cp += 3; \
122*10465441SEvalZero   } else { \
123*10465441SEvalZero     (f) = lwip_htons((u16_t)*cp++); \
124*10465441SEvalZero   } \
125*10465441SEvalZero }
126*10465441SEvalZero 
127*10465441SEvalZero /* Helper structures for unaligned *u32_t and *u16_t accesses */
128*10465441SEvalZero #ifdef PACK_STRUCT_USE_INCLUDES
129*10465441SEvalZero #  include "arch/bpstruct.h"
130*10465441SEvalZero #endif
131*10465441SEvalZero PACK_STRUCT_BEGIN
132*10465441SEvalZero struct vj_u32_t {
133*10465441SEvalZero   PACK_STRUCT_FIELD(u32_t v);
134*10465441SEvalZero } PACK_STRUCT_STRUCT;
135*10465441SEvalZero PACK_STRUCT_END
136*10465441SEvalZero #ifdef PACK_STRUCT_USE_INCLUDES
137*10465441SEvalZero #  include "arch/epstruct.h"
138*10465441SEvalZero #endif
139*10465441SEvalZero 
140*10465441SEvalZero #ifdef PACK_STRUCT_USE_INCLUDES
141*10465441SEvalZero #  include "arch/bpstruct.h"
142*10465441SEvalZero #endif
143*10465441SEvalZero PACK_STRUCT_BEGIN
144*10465441SEvalZero struct vj_u16_t {
145*10465441SEvalZero   PACK_STRUCT_FIELD(u16_t v);
146*10465441SEvalZero } PACK_STRUCT_STRUCT;
147*10465441SEvalZero PACK_STRUCT_END
148*10465441SEvalZero #ifdef PACK_STRUCT_USE_INCLUDES
149*10465441SEvalZero #  include "arch/epstruct.h"
150*10465441SEvalZero #endif
151*10465441SEvalZero 
152*10465441SEvalZero /*
153*10465441SEvalZero  * vj_compress_tcp - Attempt to do Van Jacobson header compression on a
154*10465441SEvalZero  * packet.  This assumes that nb and comp are not null and that the first
155*10465441SEvalZero  * buffer of the chain contains a valid IP header.
156*10465441SEvalZero  * Return the VJ type code indicating whether or not the packet was
157*10465441SEvalZero  * compressed.
158*10465441SEvalZero  */
159*10465441SEvalZero u8_t
vj_compress_tcp(struct vjcompress * comp,struct pbuf ** pb)160*10465441SEvalZero vj_compress_tcp(struct vjcompress *comp, struct pbuf **pb)
161*10465441SEvalZero {
162*10465441SEvalZero   struct pbuf *np = *pb;
163*10465441SEvalZero   struct ip_hdr *ip = (struct ip_hdr *)np->payload;
164*10465441SEvalZero   struct cstate *cs = comp->last_cs->cs_next;
165*10465441SEvalZero   u16_t ilen = IPH_HL(ip);
166*10465441SEvalZero   u16_t hlen;
167*10465441SEvalZero   struct tcp_hdr *oth;
168*10465441SEvalZero   struct tcp_hdr *th;
169*10465441SEvalZero   u16_t deltaS, deltaA = 0;
170*10465441SEvalZero   u32_t deltaL;
171*10465441SEvalZero   u32_t changes = 0;
172*10465441SEvalZero   u8_t new_seq[16];
173*10465441SEvalZero   u8_t *cp = new_seq;
174*10465441SEvalZero 
175*10465441SEvalZero   /*
176*10465441SEvalZero    * Check that the packet is IP proto TCP.
177*10465441SEvalZero    */
178*10465441SEvalZero   if (IPH_PROTO(ip) != IP_PROTO_TCP) {
179*10465441SEvalZero     return (TYPE_IP);
180*10465441SEvalZero   }
181*10465441SEvalZero 
182*10465441SEvalZero   /*
183*10465441SEvalZero    * Bail if this is an IP fragment or if the TCP packet isn't
184*10465441SEvalZero    * `compressible' (i.e., ACK isn't set or some other control bit is
185*10465441SEvalZero    * set).
186*10465441SEvalZero    */
187*10465441SEvalZero   if ((IPH_OFFSET(ip) & PP_HTONS(0x3fff)) || np->tot_len < 40) {
188*10465441SEvalZero     return (TYPE_IP);
189*10465441SEvalZero   }
190*10465441SEvalZero   th = (struct tcp_hdr *)&((struct vj_u32_t*)ip)[ilen];
191*10465441SEvalZero   if ((TCPH_FLAGS(th) & (TCP_SYN|TCP_FIN|TCP_RST|TCP_ACK)) != TCP_ACK) {
192*10465441SEvalZero     return (TYPE_IP);
193*10465441SEvalZero   }
194*10465441SEvalZero 
195*10465441SEvalZero   /* Check that the TCP/IP headers are contained in the first buffer. */
196*10465441SEvalZero   hlen = ilen + TCPH_HDRLEN(th);
197*10465441SEvalZero   hlen <<= 2;
198*10465441SEvalZero   if (np->len < hlen) {
199*10465441SEvalZero     PPPDEBUG(LOG_INFO, ("vj_compress_tcp: header len %d spans buffers\n", hlen));
200*10465441SEvalZero     return (TYPE_IP);
201*10465441SEvalZero   }
202*10465441SEvalZero 
203*10465441SEvalZero   /* TCP stack requires that we don't change the packet payload, therefore we copy
204*10465441SEvalZero    * the whole packet before compression. */
205*10465441SEvalZero   np = pbuf_clone(PBUF_RAW, PBUF_RAM, *pb);
206*10465441SEvalZero   if (!np) {
207*10465441SEvalZero     return (TYPE_IP);
208*10465441SEvalZero   }
209*10465441SEvalZero 
210*10465441SEvalZero   *pb = np;
211*10465441SEvalZero   ip = (struct ip_hdr *)np->payload;
212*10465441SEvalZero 
213*10465441SEvalZero   /*
214*10465441SEvalZero    * Packet is compressible -- we're going to send either a
215*10465441SEvalZero    * COMPRESSED_TCP or UNCOMPRESSED_TCP packet.  Either way we need
216*10465441SEvalZero    * to locate (or create) the connection state.  Special case the
217*10465441SEvalZero    * most recently used connection since it's most likely to be used
218*10465441SEvalZero    * again & we don't have to do any reordering if it's used.
219*10465441SEvalZero    */
220*10465441SEvalZero   INCR(vjs_packets);
221*10465441SEvalZero   if (!ip4_addr_cmp(&ip->src, &cs->cs_ip.src)
222*10465441SEvalZero       || !ip4_addr_cmp(&ip->dest, &cs->cs_ip.dest)
223*10465441SEvalZero       || (*(struct vj_u32_t*)th).v != (((struct vj_u32_t*)&cs->cs_ip)[IPH_HL(&cs->cs_ip)]).v) {
224*10465441SEvalZero     /*
225*10465441SEvalZero      * Wasn't the first -- search for it.
226*10465441SEvalZero      *
227*10465441SEvalZero      * States are kept in a circularly linked list with
228*10465441SEvalZero      * last_cs pointing to the end of the list.  The
229*10465441SEvalZero      * list is kept in lru order by moving a state to the
230*10465441SEvalZero      * head of the list whenever it is referenced.  Since
231*10465441SEvalZero      * the list is short and, empirically, the connection
232*10465441SEvalZero      * we want is almost always near the front, we locate
233*10465441SEvalZero      * states via linear search.  If we don't find a state
234*10465441SEvalZero      * for the datagram, the oldest state is (re-)used.
235*10465441SEvalZero      */
236*10465441SEvalZero     struct cstate *lcs;
237*10465441SEvalZero     struct cstate *lastcs = comp->last_cs;
238*10465441SEvalZero 
239*10465441SEvalZero     do {
240*10465441SEvalZero       lcs = cs; cs = cs->cs_next;
241*10465441SEvalZero       INCR(vjs_searches);
242*10465441SEvalZero       if (ip4_addr_cmp(&ip->src, &cs->cs_ip.src)
243*10465441SEvalZero           && ip4_addr_cmp(&ip->dest, &cs->cs_ip.dest)
244*10465441SEvalZero           && (*(struct vj_u32_t*)th).v == (((struct vj_u32_t*)&cs->cs_ip)[IPH_HL(&cs->cs_ip)]).v) {
245*10465441SEvalZero         goto found;
246*10465441SEvalZero       }
247*10465441SEvalZero     } while (cs != lastcs);
248*10465441SEvalZero 
249*10465441SEvalZero     /*
250*10465441SEvalZero      * Didn't find it -- re-use oldest cstate.  Send an
251*10465441SEvalZero      * uncompressed packet that tells the other side what
252*10465441SEvalZero      * connection number we're using for this conversation.
253*10465441SEvalZero      * Note that since the state list is circular, the oldest
254*10465441SEvalZero      * state points to the newest and we only need to set
255*10465441SEvalZero      * last_cs to update the lru linkage.
256*10465441SEvalZero      */
257*10465441SEvalZero     INCR(vjs_misses);
258*10465441SEvalZero     comp->last_cs = lcs;
259*10465441SEvalZero     goto uncompressed;
260*10465441SEvalZero 
261*10465441SEvalZero     found:
262*10465441SEvalZero     /*
263*10465441SEvalZero      * Found it -- move to the front on the connection list.
264*10465441SEvalZero      */
265*10465441SEvalZero     if (cs == lastcs) {
266*10465441SEvalZero       comp->last_cs = lcs;
267*10465441SEvalZero     } else {
268*10465441SEvalZero       lcs->cs_next = cs->cs_next;
269*10465441SEvalZero       cs->cs_next = lastcs->cs_next;
270*10465441SEvalZero       lastcs->cs_next = cs;
271*10465441SEvalZero     }
272*10465441SEvalZero   }
273*10465441SEvalZero 
274*10465441SEvalZero   oth = (struct tcp_hdr *)&((struct vj_u32_t*)&cs->cs_ip)[ilen];
275*10465441SEvalZero   deltaS = ilen;
276*10465441SEvalZero 
277*10465441SEvalZero   /*
278*10465441SEvalZero    * Make sure that only what we expect to change changed. The first
279*10465441SEvalZero    * line of the `if' checks the IP protocol version, header length &
280*10465441SEvalZero    * type of service.  The 2nd line checks the "Don't fragment" bit.
281*10465441SEvalZero    * The 3rd line checks the time-to-live and protocol (the protocol
282*10465441SEvalZero    * check is unnecessary but costless).  The 4th line checks the TCP
283*10465441SEvalZero    * header length.  The 5th line checks IP options, if any.  The 6th
284*10465441SEvalZero    * line checks TCP options, if any.  If any of these things are
285*10465441SEvalZero    * different between the previous & current datagram, we send the
286*10465441SEvalZero    * current datagram `uncompressed'.
287*10465441SEvalZero    */
288*10465441SEvalZero   if ((((struct vj_u16_t*)ip)[0]).v != (((struct vj_u16_t*)&cs->cs_ip)[0]).v
289*10465441SEvalZero       || (((struct vj_u16_t*)ip)[3]).v != (((struct vj_u16_t*)&cs->cs_ip)[3]).v
290*10465441SEvalZero       || (((struct vj_u16_t*)ip)[4]).v != (((struct vj_u16_t*)&cs->cs_ip)[4]).v
291*10465441SEvalZero       || TCPH_HDRLEN(th) != TCPH_HDRLEN(oth)
292*10465441SEvalZero       || (deltaS > 5 && BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2))
293*10465441SEvalZero       || (TCPH_HDRLEN(th) > 5 && BCMP(th + 1, oth + 1, (TCPH_HDRLEN(th) - 5) << 2))) {
294*10465441SEvalZero     goto uncompressed;
295*10465441SEvalZero   }
296*10465441SEvalZero 
297*10465441SEvalZero   /*
298*10465441SEvalZero    * Figure out which of the changing fields changed.  The
299*10465441SEvalZero    * receiver expects changes in the order: urgent, window,
300*10465441SEvalZero    * ack, seq (the order minimizes the number of temporaries
301*10465441SEvalZero    * needed in this section of code).
302*10465441SEvalZero    */
303*10465441SEvalZero   if (TCPH_FLAGS(th) & TCP_URG) {
304*10465441SEvalZero     deltaS = lwip_ntohs(th->urgp);
305*10465441SEvalZero     ENCODEZ(deltaS);
306*10465441SEvalZero     changes |= NEW_U;
307*10465441SEvalZero   } else if (th->urgp != oth->urgp) {
308*10465441SEvalZero     /* argh! URG not set but urp changed -- a sensible
309*10465441SEvalZero      * implementation should never do this but RFC793
310*10465441SEvalZero      * doesn't prohibit the change so we have to deal
311*10465441SEvalZero      * with it. */
312*10465441SEvalZero     goto uncompressed;
313*10465441SEvalZero   }
314*10465441SEvalZero 
315*10465441SEvalZero   if ((deltaS = (u16_t)(lwip_ntohs(th->wnd) - lwip_ntohs(oth->wnd))) != 0) {
316*10465441SEvalZero     ENCODE(deltaS);
317*10465441SEvalZero     changes |= NEW_W;
318*10465441SEvalZero   }
319*10465441SEvalZero 
320*10465441SEvalZero   if ((deltaL = lwip_ntohl(th->ackno) - lwip_ntohl(oth->ackno)) != 0) {
321*10465441SEvalZero     if (deltaL > 0xffff) {
322*10465441SEvalZero       goto uncompressed;
323*10465441SEvalZero     }
324*10465441SEvalZero     deltaA = (u16_t)deltaL;
325*10465441SEvalZero     ENCODE(deltaA);
326*10465441SEvalZero     changes |= NEW_A;
327*10465441SEvalZero   }
328*10465441SEvalZero 
329*10465441SEvalZero   if ((deltaL = lwip_ntohl(th->seqno) - lwip_ntohl(oth->seqno)) != 0) {
330*10465441SEvalZero     if (deltaL > 0xffff) {
331*10465441SEvalZero       goto uncompressed;
332*10465441SEvalZero     }
333*10465441SEvalZero     deltaS = (u16_t)deltaL;
334*10465441SEvalZero     ENCODE(deltaS);
335*10465441SEvalZero     changes |= NEW_S;
336*10465441SEvalZero   }
337*10465441SEvalZero 
338*10465441SEvalZero   switch(changes) {
339*10465441SEvalZero   case 0:
340*10465441SEvalZero     /*
341*10465441SEvalZero      * Nothing changed. If this packet contains data and the
342*10465441SEvalZero      * last one didn't, this is probably a data packet following
343*10465441SEvalZero      * an ack (normal on an interactive connection) and we send
344*10465441SEvalZero      * it compressed.  Otherwise it's probably a retransmit,
345*10465441SEvalZero      * retransmitted ack or window probe.  Send it uncompressed
346*10465441SEvalZero      * in case the other side missed the compressed version.
347*10465441SEvalZero      */
348*10465441SEvalZero     if (IPH_LEN(ip) != IPH_LEN(&cs->cs_ip) &&
349*10465441SEvalZero       lwip_ntohs(IPH_LEN(&cs->cs_ip)) == hlen) {
350*10465441SEvalZero       break;
351*10465441SEvalZero     }
352*10465441SEvalZero     /* no break */
353*10465441SEvalZero     /* fall through */
354*10465441SEvalZero 
355*10465441SEvalZero   case SPECIAL_I:
356*10465441SEvalZero   case SPECIAL_D:
357*10465441SEvalZero     /*
358*10465441SEvalZero      * actual changes match one of our special case encodings --
359*10465441SEvalZero      * send packet uncompressed.
360*10465441SEvalZero      */
361*10465441SEvalZero     goto uncompressed;
362*10465441SEvalZero 
363*10465441SEvalZero   case NEW_S|NEW_A:
364*10465441SEvalZero     if (deltaS == deltaA && deltaS == lwip_ntohs(IPH_LEN(&cs->cs_ip)) - hlen) {
365*10465441SEvalZero       /* special case for echoed terminal traffic */
366*10465441SEvalZero       changes = SPECIAL_I;
367*10465441SEvalZero       cp = new_seq;
368*10465441SEvalZero     }
369*10465441SEvalZero     break;
370*10465441SEvalZero 
371*10465441SEvalZero   case NEW_S:
372*10465441SEvalZero     if (deltaS == lwip_ntohs(IPH_LEN(&cs->cs_ip)) - hlen) {
373*10465441SEvalZero       /* special case for data xfer */
374*10465441SEvalZero       changes = SPECIAL_D;
375*10465441SEvalZero       cp = new_seq;
376*10465441SEvalZero     }
377*10465441SEvalZero     break;
378*10465441SEvalZero   default:
379*10465441SEvalZero      break;
380*10465441SEvalZero   }
381*10465441SEvalZero 
382*10465441SEvalZero   deltaS = (u16_t)(lwip_ntohs(IPH_ID(ip)) - lwip_ntohs(IPH_ID(&cs->cs_ip)));
383*10465441SEvalZero   if (deltaS != 1) {
384*10465441SEvalZero     ENCODEZ(deltaS);
385*10465441SEvalZero     changes |= NEW_I;
386*10465441SEvalZero   }
387*10465441SEvalZero   if (TCPH_FLAGS(th) & TCP_PSH) {
388*10465441SEvalZero     changes |= TCP_PUSH_BIT;
389*10465441SEvalZero   }
390*10465441SEvalZero   /*
391*10465441SEvalZero    * Grab the cksum before we overwrite it below.  Then update our
392*10465441SEvalZero    * state with this packet's header.
393*10465441SEvalZero    */
394*10465441SEvalZero   deltaA = lwip_ntohs(th->chksum);
395*10465441SEvalZero   MEMCPY(&cs->cs_ip, ip, hlen);
396*10465441SEvalZero 
397*10465441SEvalZero   /*
398*10465441SEvalZero    * We want to use the original packet as our compressed packet.
399*10465441SEvalZero    * (cp - new_seq) is the number of bytes we need for compressed
400*10465441SEvalZero    * sequence numbers.  In addition we need one byte for the change
401*10465441SEvalZero    * mask, one for the connection id and two for the tcp checksum.
402*10465441SEvalZero    * So, (cp - new_seq) + 4 bytes of header are needed.  hlen is how
403*10465441SEvalZero    * many bytes of the original packet to toss so subtract the two to
404*10465441SEvalZero    * get the new packet size.
405*10465441SEvalZero    */
406*10465441SEvalZero   deltaS = (u16_t)(cp - new_seq);
407*10465441SEvalZero   if (!comp->compressSlot || comp->last_xmit != cs->cs_id) {
408*10465441SEvalZero     comp->last_xmit = cs->cs_id;
409*10465441SEvalZero     hlen -= deltaS + 4;
410*10465441SEvalZero     if (pbuf_remove_header(np, hlen)){
411*10465441SEvalZero       /* Can we cope with this failing?  Just assert for now */
412*10465441SEvalZero       LWIP_ASSERT("pbuf_remove_header failed\n", 0);
413*10465441SEvalZero     }
414*10465441SEvalZero     cp = (u8_t*)np->payload;
415*10465441SEvalZero     *cp++ = (u8_t)(changes | NEW_C);
416*10465441SEvalZero     *cp++ = cs->cs_id;
417*10465441SEvalZero   } else {
418*10465441SEvalZero     hlen -= deltaS + 3;
419*10465441SEvalZero     if (pbuf_remove_header(np, hlen)) {
420*10465441SEvalZero       /* Can we cope with this failing?  Just assert for now */
421*10465441SEvalZero       LWIP_ASSERT("pbuf_remove_header failed\n", 0);
422*10465441SEvalZero     }
423*10465441SEvalZero     cp = (u8_t*)np->payload;
424*10465441SEvalZero     *cp++ = (u8_t)changes;
425*10465441SEvalZero   }
426*10465441SEvalZero   *cp++ = (u8_t)(deltaA >> 8);
427*10465441SEvalZero   *cp++ = (u8_t)deltaA;
428*10465441SEvalZero   MEMCPY(cp, new_seq, deltaS);
429*10465441SEvalZero   INCR(vjs_compressed);
430*10465441SEvalZero   return (TYPE_COMPRESSED_TCP);
431*10465441SEvalZero 
432*10465441SEvalZero   /*
433*10465441SEvalZero    * Update connection state cs & send uncompressed packet (that is,
434*10465441SEvalZero    * a regular ip/tcp packet but with the 'conversation id' we hope
435*10465441SEvalZero    * to use on future compressed packets in the protocol field).
436*10465441SEvalZero    */
437*10465441SEvalZero uncompressed:
438*10465441SEvalZero   MEMCPY(&cs->cs_ip, ip, hlen);
439*10465441SEvalZero   IPH_PROTO_SET(ip, cs->cs_id);
440*10465441SEvalZero   comp->last_xmit = cs->cs_id;
441*10465441SEvalZero   return (TYPE_UNCOMPRESSED_TCP);
442*10465441SEvalZero }
443*10465441SEvalZero 
444*10465441SEvalZero /*
445*10465441SEvalZero  * Called when we may have missed a packet.
446*10465441SEvalZero  */
447*10465441SEvalZero void
vj_uncompress_err(struct vjcompress * comp)448*10465441SEvalZero vj_uncompress_err(struct vjcompress *comp)
449*10465441SEvalZero {
450*10465441SEvalZero   comp->flags |= VJF_TOSS;
451*10465441SEvalZero   INCR(vjs_errorin);
452*10465441SEvalZero }
453*10465441SEvalZero 
454*10465441SEvalZero /*
455*10465441SEvalZero  * "Uncompress" a packet of type TYPE_UNCOMPRESSED_TCP.
456*10465441SEvalZero  * Return 0 on success, -1 on failure.
457*10465441SEvalZero  */
458*10465441SEvalZero int
vj_uncompress_uncomp(struct pbuf * nb,struct vjcompress * comp)459*10465441SEvalZero vj_uncompress_uncomp(struct pbuf *nb, struct vjcompress *comp)
460*10465441SEvalZero {
461*10465441SEvalZero   u32_t hlen;
462*10465441SEvalZero   struct cstate *cs;
463*10465441SEvalZero   struct ip_hdr *ip;
464*10465441SEvalZero 
465*10465441SEvalZero   ip = (struct ip_hdr *)nb->payload;
466*10465441SEvalZero   hlen = IPH_HL(ip) << 2;
467*10465441SEvalZero   if (IPH_PROTO(ip) >= MAX_SLOTS
468*10465441SEvalZero       || hlen + sizeof(struct tcp_hdr) > nb->len
469*10465441SEvalZero       || (hlen += TCPH_HDRLEN_BYTES((struct tcp_hdr *)&((char *)ip)[hlen]))
470*10465441SEvalZero           > nb->len
471*10465441SEvalZero       || hlen > MAX_HDR) {
472*10465441SEvalZero     PPPDEBUG(LOG_INFO, ("vj_uncompress_uncomp: bad cid=%d, hlen=%d buflen=%d\n",
473*10465441SEvalZero       IPH_PROTO(ip), hlen, nb->len));
474*10465441SEvalZero     vj_uncompress_err(comp);
475*10465441SEvalZero     return -1;
476*10465441SEvalZero   }
477*10465441SEvalZero   cs = &comp->rstate[comp->last_recv = IPH_PROTO(ip)];
478*10465441SEvalZero   comp->flags &=~ VJF_TOSS;
479*10465441SEvalZero   IPH_PROTO_SET(ip, IP_PROTO_TCP);
480*10465441SEvalZero   /* copy from/to bigger buffers checked above instead of cs->cs_ip and ip
481*10465441SEvalZero      just to help static code analysis to see this is correct ;-) */
482*10465441SEvalZero   MEMCPY(&cs->cs_hdr, nb->payload, hlen);
483*10465441SEvalZero   cs->cs_hlen = (u16_t)hlen;
484*10465441SEvalZero   INCR(vjs_uncompressedin);
485*10465441SEvalZero   return 0;
486*10465441SEvalZero }
487*10465441SEvalZero 
488*10465441SEvalZero /*
489*10465441SEvalZero  * Uncompress a packet of type TYPE_COMPRESSED_TCP.
490*10465441SEvalZero  * The packet is composed of a buffer chain and the first buffer
491*10465441SEvalZero  * must contain an accurate chain length.
492*10465441SEvalZero  * The first buffer must include the entire compressed TCP/IP header.
493*10465441SEvalZero  * This procedure replaces the compressed header with the uncompressed
494*10465441SEvalZero  * header and returns the length of the VJ header.
495*10465441SEvalZero  */
496*10465441SEvalZero int
vj_uncompress_tcp(struct pbuf ** nb,struct vjcompress * comp)497*10465441SEvalZero vj_uncompress_tcp(struct pbuf **nb, struct vjcompress *comp)
498*10465441SEvalZero {
499*10465441SEvalZero   u8_t *cp;
500*10465441SEvalZero   struct tcp_hdr *th;
501*10465441SEvalZero   struct cstate *cs;
502*10465441SEvalZero   struct vj_u16_t *bp;
503*10465441SEvalZero   struct pbuf *n0 = *nb;
504*10465441SEvalZero   u32_t tmp;
505*10465441SEvalZero   u32_t vjlen, hlen, changes;
506*10465441SEvalZero 
507*10465441SEvalZero   INCR(vjs_compressedin);
508*10465441SEvalZero   cp = (u8_t*)n0->payload;
509*10465441SEvalZero   changes = *cp++;
510*10465441SEvalZero   if (changes & NEW_C) {
511*10465441SEvalZero     /*
512*10465441SEvalZero      * Make sure the state index is in range, then grab the state.
513*10465441SEvalZero      * If we have a good state index, clear the 'discard' flag.
514*10465441SEvalZero      */
515*10465441SEvalZero     if (*cp >= MAX_SLOTS) {
516*10465441SEvalZero       PPPDEBUG(LOG_INFO, ("vj_uncompress_tcp: bad cid=%d\n", *cp));
517*10465441SEvalZero       goto bad;
518*10465441SEvalZero     }
519*10465441SEvalZero 
520*10465441SEvalZero     comp->flags &=~ VJF_TOSS;
521*10465441SEvalZero     comp->last_recv = *cp++;
522*10465441SEvalZero   } else {
523*10465441SEvalZero     /*
524*10465441SEvalZero      * this packet has an implicit state index.  If we've
525*10465441SEvalZero      * had a line error since the last time we got an
526*10465441SEvalZero      * explicit state index, we have to toss the packet.
527*10465441SEvalZero      */
528*10465441SEvalZero     if (comp->flags & VJF_TOSS) {
529*10465441SEvalZero       PPPDEBUG(LOG_INFO, ("vj_uncompress_tcp: tossing\n"));
530*10465441SEvalZero       INCR(vjs_tossed);
531*10465441SEvalZero       return (-1);
532*10465441SEvalZero     }
533*10465441SEvalZero   }
534*10465441SEvalZero   cs = &comp->rstate[comp->last_recv];
535*10465441SEvalZero   hlen = IPH_HL(&cs->cs_ip) << 2;
536*10465441SEvalZero   th = (struct tcp_hdr *)&((u8_t*)&cs->cs_ip)[hlen];
537*10465441SEvalZero   th->chksum = lwip_htons((*cp << 8) | cp[1]);
538*10465441SEvalZero   cp += 2;
539*10465441SEvalZero   if (changes & TCP_PUSH_BIT) {
540*10465441SEvalZero     TCPH_SET_FLAG(th, TCP_PSH);
541*10465441SEvalZero   } else {
542*10465441SEvalZero     TCPH_UNSET_FLAG(th, TCP_PSH);
543*10465441SEvalZero   }
544*10465441SEvalZero 
545*10465441SEvalZero   switch (changes & SPECIALS_MASK) {
546*10465441SEvalZero   case SPECIAL_I:
547*10465441SEvalZero     {
548*10465441SEvalZero       u32_t i = lwip_ntohs(IPH_LEN(&cs->cs_ip)) - cs->cs_hlen;
549*10465441SEvalZero       /* some compilers can't nest inline assembler.. */
550*10465441SEvalZero       tmp = lwip_ntohl(th->ackno) + i;
551*10465441SEvalZero       th->ackno = lwip_htonl(tmp);
552*10465441SEvalZero       tmp = lwip_ntohl(th->seqno) + i;
553*10465441SEvalZero       th->seqno = lwip_htonl(tmp);
554*10465441SEvalZero     }
555*10465441SEvalZero     break;
556*10465441SEvalZero 
557*10465441SEvalZero   case SPECIAL_D:
558*10465441SEvalZero     /* some compilers can't nest inline assembler.. */
559*10465441SEvalZero     tmp = lwip_ntohl(th->seqno) + lwip_ntohs(IPH_LEN(&cs->cs_ip)) - cs->cs_hlen;
560*10465441SEvalZero     th->seqno = lwip_htonl(tmp);
561*10465441SEvalZero     break;
562*10465441SEvalZero 
563*10465441SEvalZero   default:
564*10465441SEvalZero     if (changes & NEW_U) {
565*10465441SEvalZero       TCPH_SET_FLAG(th, TCP_URG);
566*10465441SEvalZero       DECODEU(th->urgp);
567*10465441SEvalZero     } else {
568*10465441SEvalZero       TCPH_UNSET_FLAG(th, TCP_URG);
569*10465441SEvalZero     }
570*10465441SEvalZero     if (changes & NEW_W) {
571*10465441SEvalZero       DECODES(th->wnd);
572*10465441SEvalZero     }
573*10465441SEvalZero     if (changes & NEW_A) {
574*10465441SEvalZero       DECODEL(th->ackno);
575*10465441SEvalZero     }
576*10465441SEvalZero     if (changes & NEW_S) {
577*10465441SEvalZero       DECODEL(th->seqno);
578*10465441SEvalZero     }
579*10465441SEvalZero     break;
580*10465441SEvalZero   }
581*10465441SEvalZero   if (changes & NEW_I) {
582*10465441SEvalZero     DECODES(cs->cs_ip._id);
583*10465441SEvalZero   } else {
584*10465441SEvalZero     IPH_ID_SET(&cs->cs_ip, lwip_ntohs(IPH_ID(&cs->cs_ip)) + 1);
585*10465441SEvalZero     IPH_ID_SET(&cs->cs_ip, lwip_htons(IPH_ID(&cs->cs_ip)));
586*10465441SEvalZero   }
587*10465441SEvalZero 
588*10465441SEvalZero   /*
589*10465441SEvalZero    * At this point, cp points to the first byte of data in the
590*10465441SEvalZero    * packet.  Fill in the IP total length and update the IP
591*10465441SEvalZero    * header checksum.
592*10465441SEvalZero    */
593*10465441SEvalZero   vjlen = (u16_t)(cp - (u8_t*)n0->payload);
594*10465441SEvalZero   if (n0->len < vjlen) {
595*10465441SEvalZero     /*
596*10465441SEvalZero      * We must have dropped some characters (crc should detect
597*10465441SEvalZero      * this but the old slip framing won't)
598*10465441SEvalZero      */
599*10465441SEvalZero     PPPDEBUG(LOG_INFO, ("vj_uncompress_tcp: head buffer %d too short %d\n",
600*10465441SEvalZero           n0->len, vjlen));
601*10465441SEvalZero     goto bad;
602*10465441SEvalZero   }
603*10465441SEvalZero 
604*10465441SEvalZero #if BYTE_ORDER == LITTLE_ENDIAN
605*10465441SEvalZero   tmp = n0->tot_len - vjlen + cs->cs_hlen;
606*10465441SEvalZero   IPH_LEN_SET(&cs->cs_ip, lwip_htons((u16_t)tmp));
607*10465441SEvalZero #else
608*10465441SEvalZero   IPH_LEN_SET(&cs->cs_ip, lwip_htons(n0->tot_len - vjlen + cs->cs_hlen));
609*10465441SEvalZero #endif
610*10465441SEvalZero 
611*10465441SEvalZero   /* recompute the ip header checksum */
612*10465441SEvalZero   bp = (struct vj_u16_t*) &cs->cs_ip;
613*10465441SEvalZero   IPH_CHKSUM_SET(&cs->cs_ip, 0);
614*10465441SEvalZero   for (tmp = 0; hlen > 0; hlen -= 2) {
615*10465441SEvalZero     tmp += (*bp++).v;
616*10465441SEvalZero   }
617*10465441SEvalZero   tmp = (tmp & 0xffff) + (tmp >> 16);
618*10465441SEvalZero   tmp = (tmp & 0xffff) + (tmp >> 16);
619*10465441SEvalZero   IPH_CHKSUM_SET(&cs->cs_ip,  (u16_t)(~tmp));
620*10465441SEvalZero 
621*10465441SEvalZero   /* Remove the compressed header and prepend the uncompressed header. */
622*10465441SEvalZero   if (pbuf_remove_header(n0, vjlen)) {
623*10465441SEvalZero     /* Can we cope with this failing?  Just assert for now */
624*10465441SEvalZero     LWIP_ASSERT("pbuf_remove_header failed\n", 0);
625*10465441SEvalZero     goto bad;
626*10465441SEvalZero   }
627*10465441SEvalZero 
628*10465441SEvalZero   if(LWIP_MEM_ALIGN(n0->payload) != n0->payload) {
629*10465441SEvalZero     struct pbuf *np;
630*10465441SEvalZero 
631*10465441SEvalZero #if IP_FORWARD
632*10465441SEvalZero     /* If IP forwarding is enabled we are using a PBUF_LINK packet type so
633*10465441SEvalZero      * the packet is being allocated with enough header space to be
634*10465441SEvalZero      * forwarded (to Ethernet for example).
635*10465441SEvalZero      */
636*10465441SEvalZero     np = pbuf_alloc(PBUF_LINK, n0->len + cs->cs_hlen, PBUF_POOL);
637*10465441SEvalZero #else /* IP_FORWARD */
638*10465441SEvalZero     np = pbuf_alloc(PBUF_RAW, n0->len + cs->cs_hlen, PBUF_POOL);
639*10465441SEvalZero #endif /* IP_FORWARD */
640*10465441SEvalZero     if(!np) {
641*10465441SEvalZero       PPPDEBUG(LOG_WARNING, ("vj_uncompress_tcp: realign failed\n"));
642*10465441SEvalZero       goto bad;
643*10465441SEvalZero     }
644*10465441SEvalZero 
645*10465441SEvalZero     if (pbuf_remove_header(np, cs->cs_hlen)) {
646*10465441SEvalZero       /* Can we cope with this failing?  Just assert for now */
647*10465441SEvalZero       LWIP_ASSERT("pbuf_remove_header failed\n", 0);
648*10465441SEvalZero       goto bad;
649*10465441SEvalZero     }
650*10465441SEvalZero 
651*10465441SEvalZero     pbuf_take(np, n0->payload, n0->len);
652*10465441SEvalZero 
653*10465441SEvalZero     if(n0->next) {
654*10465441SEvalZero       pbuf_chain(np, n0->next);
655*10465441SEvalZero       pbuf_dechain(n0);
656*10465441SEvalZero     }
657*10465441SEvalZero     pbuf_free(n0);
658*10465441SEvalZero     n0 = np;
659*10465441SEvalZero   }
660*10465441SEvalZero 
661*10465441SEvalZero   if (pbuf_add_header(n0, cs->cs_hlen)) {
662*10465441SEvalZero     struct pbuf *np;
663*10465441SEvalZero 
664*10465441SEvalZero     LWIP_ASSERT("vj_uncompress_tcp: cs->cs_hlen <= PBUF_POOL_BUFSIZE", cs->cs_hlen <= PBUF_POOL_BUFSIZE);
665*10465441SEvalZero     np = pbuf_alloc(PBUF_RAW, cs->cs_hlen, PBUF_POOL);
666*10465441SEvalZero     if(!np) {
667*10465441SEvalZero       PPPDEBUG(LOG_WARNING, ("vj_uncompress_tcp: prepend failed\n"));
668*10465441SEvalZero       goto bad;
669*10465441SEvalZero     }
670*10465441SEvalZero     pbuf_cat(np, n0);
671*10465441SEvalZero     n0 = np;
672*10465441SEvalZero   }
673*10465441SEvalZero   LWIP_ASSERT("n0->len >= cs->cs_hlen", n0->len >= cs->cs_hlen);
674*10465441SEvalZero   MEMCPY(n0->payload, &cs->cs_ip, cs->cs_hlen);
675*10465441SEvalZero 
676*10465441SEvalZero   *nb = n0;
677*10465441SEvalZero 
678*10465441SEvalZero   return vjlen;
679*10465441SEvalZero 
680*10465441SEvalZero bad:
681*10465441SEvalZero   vj_uncompress_err(comp);
682*10465441SEvalZero   return (-1);
683*10465441SEvalZero }
684*10465441SEvalZero 
685*10465441SEvalZero #endif /* PPP_SUPPORT && VJ_SUPPORT */
686