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