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