Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers vj.c Source File

vj.c

00001 /*
00002  * Routines to compress and uncompess tcp packets (for transmission
00003  * over low speed serial lines.
00004  *
00005  * Copyright (c) 1989 Regents of the University of California.
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms are permitted
00009  * provided that the above copyright notice and this paragraph are
00010  * duplicated in all such forms and that any documentation,
00011  * advertising materials, and other materials related to such
00012  * distribution and use acknowledge that the software was developed
00013  * by the University of California, Berkeley.  The name of the
00014  * University may not be used to endorse or promote products derived
00015  * from this software without specific prior written permission.
00016  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
00017  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
00018  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00019  *
00020  * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
00021  *   Initial distribution.
00022  *
00023  * Modified June 1993 by Paul Mackerras, paulus@cs.anu.edu.au,
00024  * so that the entire packet being decompressed doesn't have
00025  * to be in contiguous memory (just the compressed header).
00026  *
00027  * Modified March 1998 by Guy Lancaster, glanca@gesn.com,
00028  * for a 16 bit processor.
00029  */
00030 
00031 #include "ppp_opts.h"
00032 #if PPP_SUPPORT && VJ_SUPPORT /* don't build if not configured for use in ppp_opts.h */
00033 #include "ppp_impl.h"
00034 #include "pppdebug.h"
00035 
00036 #include "vj.h"
00037 
00038 #include <string.h>
00039 
00040 #if LINK_STATS
00041 #define INCR(counter) ++comp->stats.counter
00042 #else
00043 #define INCR(counter)
00044 #endif
00045 
00046 void
00047 vj_compress_init(struct vjcompress *comp)
00048 {
00049   u8_t i;
00050   struct cstate *tstate = comp->tstate;
00051 
00052 #if MAX_SLOTS == 0
00053   memset((char *)comp, 0, sizeof(*comp));
00054 #endif
00055   comp->maxSlotIndex = MAX_SLOTS - 1;
00056   comp->compressSlot = 0;    /* Disable slot ID compression by default. */
00057   for (i = MAX_SLOTS - 1; i > 0; --i) {
00058     tstate[i].cs_id = i;
00059     tstate[i].cs_next = &tstate[i - 1];
00060   }
00061   tstate[0].cs_next = &tstate[MAX_SLOTS - 1];
00062   tstate[0].cs_id = 0;
00063   comp->last_cs = &tstate[0];
00064   comp->last_recv = 255;
00065   comp->last_xmit = 255;
00066   comp->flags = VJF_TOSS;
00067 }
00068 
00069 
00070 /* ENCODE encodes a number that is known to be non-zero.  ENCODEZ
00071  * checks for zero (since zero has to be encoded in the long, 3 byte
00072  * form).
00073  */
00074 #define ENCODE(n) { \
00075   if ((u16_t)(n) >= 256) { \
00076     *cp++ = 0; \
00077     cp[1] = (u8_t)(n); \
00078     cp[0] = (u8_t)((n) >> 8); \
00079     cp += 2; \
00080   } else { \
00081     *cp++ = (u8_t)(n); \
00082   } \
00083 }
00084 #define ENCODEZ(n) { \
00085   if ((u16_t)(n) >= 256 || (u16_t)(n) == 0) { \
00086     *cp++ = 0; \
00087     cp[1] = (u8_t)(n); \
00088     cp[0] = (u8_t)((n) >> 8); \
00089     cp += 2; \
00090   } else { \
00091     *cp++ = (u8_t)(n); \
00092   } \
00093 }
00094 
00095 #define DECODEL(f) { \
00096   if (*cp == 0) {\
00097     u32_t tmp_ = ppp_ntohl(f) + ((cp[1] << 8) | cp[2]); \
00098     (f) = ppp_htonl(tmp_); \
00099     cp += 3; \
00100   } else { \
00101     u32_t tmp_ = ppp_ntohl(f) + (u32_t)*cp++; \
00102     (f) = ppp_htonl(tmp_); \
00103   } \
00104 }
00105 
00106 #define DECODES(f) { \
00107   if (*cp == 0) {\
00108     u16_t tmp_ = ppp_ntohs(f) + (((u16_t)cp[1] << 8) | cp[2]); \
00109     (f) = ppp_htons(tmp_); \
00110     cp += 3; \
00111   } else { \
00112     u16_t tmp_ = ppp_ntohs(f) + (u16_t)*cp++; \
00113     (f) = ppp_htons(tmp_); \
00114   } \
00115 }
00116 
00117 #define DECODEU(f) { \
00118   if (*cp == 0) {\
00119     (f) = ppp_htons(((u16_t)cp[1] << 8) | cp[2]); \
00120     cp += 3; \
00121   } else { \
00122     (f) = ppp_htons((u16_t)*cp++); \
00123   } \
00124 }
00125 
00126 /* Helper structures for unaligned *u32_t and *u16_t accesses */
00127 #ifdef PACK_STRUCT_USE_INCLUDES
00128 #  include "arch/bpstruct.h"
00129 #endif
00130 PACK_STRUCT_BEGIN
00131 struct vj_u32_t {
00132   PACK_STRUCT_FIELD(u32_t v);
00133 } PACK_STRUCT_STRUCT;
00134 PACK_STRUCT_END
00135 #ifdef PACK_STRUCT_USE_INCLUDES
00136 #  include "arch/epstruct.h"
00137 #endif
00138 
00139 #ifdef PACK_STRUCT_USE_INCLUDES
00140 #  include "arch/bpstruct.h"
00141 #endif
00142 PACK_STRUCT_BEGIN
00143 struct vj_u16_t {
00144   PACK_STRUCT_FIELD(u16_t v);
00145 } PACK_STRUCT_STRUCT;
00146 PACK_STRUCT_END
00147 #ifdef PACK_STRUCT_USE_INCLUDES
00148 #  include "arch/epstruct.h"
00149 #endif
00150 
00151 /*
00152  * vj_compress_tcp - Attempt to do Van Jacobson header compression on a
00153  * packet.  This assumes that nb and comp are not null and that the first
00154  * buffer of the chain contains a valid IP header.
00155  * Return the VJ type code indicating whether or not the packet was
00156  * compressed.
00157  */
00158 u8_t
00159 vj_compress_tcp(struct vjcompress *comp, struct pbuf **pb)
00160 {
00161   struct pbuf *np = *pb;
00162   struct ip_hdr *ip = (struct ip_hdr *)np->payload;
00163   struct cstate *cs = comp->last_cs->cs_next;
00164   u16_t ilen = IPH_HL(ip);
00165   u16_t hlen;
00166   struct tcp_hdr *oth;
00167   struct tcp_hdr *th;
00168   u16_t deltaS, deltaA = 0;
00169   u32_t deltaL;
00170   u32_t changes = 0;
00171   u8_t new_seq[16];
00172   u8_t *cp = new_seq;
00173 
00174   /*
00175    * Check that the packet is IP proto TCP.
00176    */
00177   if (IPH_PROTO(ip) != IP_PROTO_TCP) {
00178     return (TYPE_IP);
00179   }
00180 
00181   /*
00182    * Bail if this is an IP fragment or if the TCP packet isn't
00183    * `compressible' (i.e., ACK isn't set or some other control bit is
00184    * set).
00185    */
00186   if ((IPH_OFFSET(ip) & PP_HTONS(0x3fff)) || np->tot_len < 40) {
00187     return (TYPE_IP);
00188   }
00189   th = (struct tcp_hdr *)&((struct vj_u32_t*)ip)[ilen];
00190   if ((TCPH_FLAGS(th) & (TCP_SYN|TCP_FIN|TCP_RST|TCP_ACK)) != TCP_ACK) {
00191     return (TYPE_IP);
00192   }
00193 
00194   /* Check that the TCP/IP headers are contained in the first buffer. */
00195   hlen = ilen + TCPH_HDRLEN(th);
00196   hlen <<= 2;
00197   if (np->len < hlen) {
00198     PPPDEBUG(LOG_INFO, ("vj_compress_tcp: header len %d spans buffers\n", hlen));
00199     return (TYPE_IP);
00200   }
00201 
00202   /* TCP stack requires that we don't change the packet payload, therefore we copy
00203    * the whole packet before compression. */
00204   np = pbuf_clone(PBUF_RAW, PBUF_RAM, *pb);
00205   if (!np) {
00206     return (TYPE_IP);
00207   }
00208 
00209   *pb = np;
00210   ip = (struct ip_hdr *)np->payload;
00211 
00212   /*
00213    * Packet is compressible -- we're going to send either a
00214    * COMPRESSED_TCP or UNCOMPRESSED_TCP packet.  Either way we need
00215    * to locate (or create) the connection state.  Special case the
00216    * most recently used connection since it's most likely to be used
00217    * again & we don't have to do any reordering if it's used.
00218    */
00219   INCR(vjs_packets);
00220   if (!ip4_addr_cmp(&ip->src, &cs->cs_ip.src)
00221       || !ip4_addr_cmp(&ip->dest, &cs->cs_ip.dest)
00222       || (*(struct vj_u32_t*)th).v != (((struct vj_u32_t*)&cs->cs_ip)[IPH_HL(&cs->cs_ip)]).v) {
00223     /*
00224      * Wasn't the first -- search for it.
00225      *
00226      * States are kept in a circularly linked list with
00227      * last_cs pointing to the end of the list.  The
00228      * list is kept in lru order by moving a state to the
00229      * head of the list whenever it is referenced.  Since
00230      * the list is short and, empirically, the connection
00231      * we want is almost always near the front, we locate
00232      * states via linear search.  If we don't find a state
00233      * for the datagram, the oldest state is (re-)used.
00234      */
00235     struct cstate *lcs;
00236     struct cstate *lastcs = comp->last_cs;
00237 
00238     do {
00239       lcs = cs; cs = cs->cs_next;
00240       INCR(vjs_searches);
00241       if (ip4_addr_cmp(&ip->src, &cs->cs_ip.src)
00242           && ip4_addr_cmp(&ip->dest, &cs->cs_ip.dest)
00243           && (*(struct vj_u32_t*)th).v == (((struct vj_u32_t*)&cs->cs_ip)[IPH_HL(&cs->cs_ip)]).v) {
00244         goto found;
00245       }
00246     } while (cs != lastcs);
00247 
00248     /*
00249      * Didn't find it -- re-use oldest cstate.  Send an
00250      * uncompressed packet that tells the other side what
00251      * connection number we're using for this conversation.
00252      * Note that since the state list is circular, the oldest
00253      * state points to the newest and we only need to set
00254      * last_cs to update the lru linkage.
00255      */
00256     INCR(vjs_misses);
00257     comp->last_cs = lcs;
00258     goto uncompressed;
00259 
00260     found:
00261     /*
00262      * Found it -- move to the front on the connection list.
00263      */
00264     if (cs == lastcs) {
00265       comp->last_cs = lcs;
00266     } else {
00267       lcs->cs_next = cs->cs_next;
00268       cs->cs_next = lastcs->cs_next;
00269       lastcs->cs_next = cs;
00270     }
00271   }
00272 
00273   oth = (struct tcp_hdr *)&((struct vj_u32_t*)&cs->cs_ip)[ilen];
00274   deltaS = ilen;
00275 
00276   /*
00277    * Make sure that only what we expect to change changed. The first
00278    * line of the `if' checks the IP protocol version, header length &
00279    * type of service.  The 2nd line checks the "Don't fragment" bit.
00280    * The 3rd line checks the time-to-live and protocol (the protocol
00281    * check is unnecessary but costless).  The 4th line checks the TCP
00282    * header length.  The 5th line checks IP options, if any.  The 6th
00283    * line checks TCP options, if any.  If any of these things are
00284    * different between the previous & current datagram, we send the
00285    * current datagram `uncompressed'.
00286    */
00287   if ((((struct vj_u16_t*)ip)[0]).v != (((struct vj_u16_t*)&cs->cs_ip)[0]).v
00288       || (((struct vj_u16_t*)ip)[3]).v != (((struct vj_u16_t*)&cs->cs_ip)[3]).v
00289       || (((struct vj_u16_t*)ip)[4]).v != (((struct vj_u16_t*)&cs->cs_ip)[4]).v
00290       || TCPH_HDRLEN(th) != TCPH_HDRLEN(oth)
00291       || (deltaS > 5 && BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2))
00292       || (TCPH_HDRLEN(th) > 5 && BCMP(th + 1, oth + 1, (TCPH_HDRLEN(th) - 5) << 2))) {
00293     goto uncompressed;
00294   }
00295 
00296   /*
00297    * Figure out which of the changing fields changed.  The
00298    * receiver expects changes in the order: urgent, window,
00299    * ack, seq (the order minimizes the number of temporaries
00300    * needed in this section of code).
00301    */
00302   if (TCPH_FLAGS(th) & TCP_URG) {
00303     deltaS = ppp_ntohs(th->urgp);
00304     ENCODEZ(deltaS);
00305     changes |= NEW_U;
00306   } else if (th->urgp != oth->urgp) {
00307     /* argh! URG not set but urp changed -- a sensible
00308      * implementation should never do this but RFC793
00309      * doesn't prohibit the change so we have to deal
00310      * with it. */
00311     goto uncompressed;
00312   }
00313 
00314   if ((deltaS = (u16_t)(ppp_ntohs(th->wnd) - ppp_ntohs(oth->wnd))) != 0) {
00315     ENCODE(deltaS);
00316     changes |= NEW_W;
00317   }
00318 
00319   if ((deltaL = ppp_ntohl(th->ackno) - ppp_ntohl(oth->ackno)) != 0) {
00320     if (deltaL > 0xffff) {
00321       goto uncompressed;
00322     }
00323     deltaA = (u16_t)deltaL;
00324     ENCODE(deltaA);
00325     changes |= NEW_A;
00326   }
00327 
00328   if ((deltaL = ppp_ntohl(th->seqno) - ppp_ntohl(oth->seqno)) != 0) {
00329     if (deltaL > 0xffff) {
00330       goto uncompressed;
00331     }
00332     deltaS = (u16_t)deltaL;
00333     ENCODE(deltaS);
00334     changes |= NEW_S;
00335   }
00336 
00337   switch(changes) {
00338   case 0:
00339     /*
00340      * Nothing changed. If this packet contains data and the
00341      * last one didn't, this is probably a data packet following
00342      * an ack (normal on an interactive connection) and we send
00343      * it compressed.  Otherwise it's probably a retransmit,
00344      * retransmitted ack or window probe.  Send it uncompressed
00345      * in case the other side missed the compressed version.
00346      */
00347     if (IPH_LEN(ip) != IPH_LEN(&cs->cs_ip) &&
00348       ppp_ntohs(IPH_LEN(&cs->cs_ip)) == hlen) {
00349       break;
00350     }
00351     /* no break */
00352     /* fall through */
00353 
00354   case SPECIAL_I:
00355   case SPECIAL_D:
00356     /*
00357      * actual changes match one of our special case encodings --
00358      * send packet uncompressed.
00359      */
00360     goto uncompressed;
00361 
00362   case NEW_S|NEW_A:
00363     if (deltaS == deltaA && deltaS == ppp_ntohs(IPH_LEN(&cs->cs_ip)) - hlen) {
00364       /* special case for echoed terminal traffic */
00365       changes = SPECIAL_I;
00366       cp = new_seq;
00367     }
00368     break;
00369 
00370   case NEW_S:
00371     if (deltaS == ppp_ntohs(IPH_LEN(&cs->cs_ip)) - hlen) {
00372       /* special case for data xfer */
00373       changes = SPECIAL_D;
00374       cp = new_seq;
00375     }
00376     break;
00377   default:
00378      break;
00379   }
00380 
00381   deltaS = (u16_t)(ppp_ntohs(IPH_ID(ip)) - ppp_ntohs(IPH_ID(&cs->cs_ip)));
00382   if (deltaS != 1) {
00383     ENCODEZ(deltaS);
00384     changes |= NEW_I;
00385   }
00386   if (TCPH_FLAGS(th) & TCP_PSH) {
00387     changes |= TCP_PUSH_BIT;
00388   }
00389   /*
00390    * Grab the cksum before we overwrite it below.  Then update our
00391    * state with this packet's header.
00392    */
00393   deltaA = ppp_ntohs(th->chksum);
00394   MEMCPY(&cs->cs_ip, ip, hlen);
00395 
00396   /*
00397    * We want to use the original packet as our compressed packet.
00398    * (cp - new_seq) is the number of bytes we need for compressed
00399    * sequence numbers.  In addition we need one byte for the change
00400    * mask, one for the connection id and two for the tcp checksum.
00401    * So, (cp - new_seq) + 4 bytes of header are needed.  hlen is how
00402    * many bytes of the original packet to toss so subtract the two to
00403    * get the new packet size.
00404    */
00405   deltaS = (u16_t)(cp - new_seq);
00406   if (!comp->compressSlot || comp->last_xmit != cs->cs_id) {
00407     comp->last_xmit = cs->cs_id;
00408     hlen -= deltaS + 4;
00409     if (pbuf_remove_header(np, hlen)){
00410       /* Can we cope with this failing?  Just assert for now */
00411       PPP_ASSERT("pbuf_remove_header failed\n", 0);
00412     }
00413     cp = (u8_t*)np->payload;
00414     *cp++ = (u8_t)(changes | NEW_C);
00415     *cp++ = cs->cs_id;
00416   } else {
00417     hlen -= deltaS + 3;
00418     if (pbuf_remove_header(np, hlen)) {
00419       /* Can we cope with this failing?  Just assert for now */
00420       PPP_ASSERT("pbuf_remove_header failed\n", 0);
00421     }
00422     cp = (u8_t*)np->payload;
00423     *cp++ = (u8_t)changes;
00424   }
00425   *cp++ = (u8_t)(deltaA >> 8);
00426   *cp++ = (u8_t)deltaA;
00427   MEMCPY(cp, new_seq, deltaS);
00428   INCR(vjs_compressed);
00429   return (TYPE_COMPRESSED_TCP);
00430 
00431   /*
00432    * Update connection state cs & send uncompressed packet (that is,
00433    * a regular ip/tcp packet but with the 'conversation id' we hope
00434    * to use on future compressed packets in the protocol field).
00435    */
00436 uncompressed:
00437   MEMCPY(&cs->cs_ip, ip, hlen);
00438   IPH_PROTO_SET(ip, cs->cs_id);
00439   comp->last_xmit = cs->cs_id;
00440   return (TYPE_UNCOMPRESSED_TCP);
00441 }
00442 
00443 /*
00444  * Called when we may have missed a packet.
00445  */
00446 void
00447 vj_uncompress_err(struct vjcompress *comp)
00448 {
00449   comp->flags |= VJF_TOSS;
00450   INCR(vjs_errorin);
00451 }
00452 
00453 /*
00454  * "Uncompress" a packet of type TYPE_UNCOMPRESSED_TCP.
00455  * Return 0 on success, -1 on failure.
00456  */
00457 int
00458 vj_uncompress_uncomp(struct pbuf *nb, struct vjcompress *comp)
00459 {
00460   u32_t hlen;
00461   struct cstate *cs;
00462   struct ip_hdr *ip;
00463 
00464   ip = (struct ip_hdr *)nb->payload;
00465   hlen = IPH_HL(ip) << 2;
00466   if (IPH_PROTO(ip) >= MAX_SLOTS
00467       || hlen + sizeof(struct tcp_hdr) > nb->len
00468       || (hlen += TCPH_HDRLEN_BYTES((struct tcp_hdr *)&((char *)ip)[hlen]))
00469           > nb->len
00470       || hlen > MAX_HDR) {
00471     PPPDEBUG(LOG_INFO, ("vj_uncompress_uncomp: bad cid=%d, hlen=%d buflen=%d\n",
00472       IPH_PROTO(ip), hlen, nb->len));
00473     vj_uncompress_err(comp);
00474     return -1;
00475   }
00476   cs = &comp->rstate[comp->last_recv = IPH_PROTO(ip)];
00477   comp->flags &=~ VJF_TOSS;
00478   IPH_PROTO_SET(ip, IP_PROTO_TCP);
00479   /* copy from/to bigger buffers checked above instead of cs->cs_ip and ip
00480      just to help static code analysis to see this is correct ;-) */
00481   MEMCPY(&cs->cs_hdr, nb->payload, hlen);
00482   cs->cs_hlen = (u16_t)hlen;
00483   INCR(vjs_uncompressedin);
00484   return 0;
00485 }
00486 
00487 /*
00488  * Uncompress a packet of type TYPE_COMPRESSED_TCP.
00489  * The packet is composed of a buffer chain and the first buffer
00490  * must contain an accurate chain length.
00491  * The first buffer must include the entire compressed TCP/IP header.
00492  * This procedure replaces the compressed header with the uncompressed
00493  * header and returns the length of the VJ header.
00494  */
00495 int
00496 vj_uncompress_tcp(struct pbuf **nb, struct vjcompress *comp)
00497 {
00498   u8_t *cp;
00499   struct tcp_hdr *th;
00500   struct cstate *cs;
00501   struct vj_u16_t *bp;
00502   struct pbuf *n0 = *nb;
00503   u32_t tmp;
00504   u32_t vjlen, hlen, changes;
00505 
00506   INCR(vjs_compressedin);
00507   cp = (u8_t*)n0->payload;
00508   changes = *cp++;
00509   if (changes & NEW_C) {
00510     /*
00511      * Make sure the state index is in range, then grab the state.
00512      * If we have a good state index, clear the 'discard' flag.
00513      */
00514     if (*cp >= MAX_SLOTS) {
00515       PPPDEBUG(LOG_INFO, ("vj_uncompress_tcp: bad cid=%d\n", *cp));
00516       goto bad;
00517     }
00518 
00519     comp->flags &=~ VJF_TOSS;
00520     comp->last_recv = *cp++;
00521   } else {
00522     /*
00523      * this packet has an implicit state index.  If we've
00524      * had a line error since the last time we got an
00525      * explicit state index, we have to toss the packet.
00526      */
00527     if (comp->flags & VJF_TOSS) {
00528       PPPDEBUG(LOG_INFO, ("vj_uncompress_tcp: tossing\n"));
00529       INCR(vjs_tossed);
00530       return (-1);
00531     }
00532   }
00533   cs = &comp->rstate[comp->last_recv];
00534   hlen = IPH_HL(&cs->cs_ip) << 2;
00535   th = (struct tcp_hdr *)&((u8_t*)&cs->cs_ip)[hlen];
00536   th->chksum = ppp_htons((*cp << 8) | cp[1]);
00537   cp += 2;
00538   if (changes & TCP_PUSH_BIT) {
00539     TCPH_SET_FLAG(th, TCP_PSH);
00540   } else {
00541     TCPH_UNSET_FLAG(th, TCP_PSH);
00542   }
00543 
00544   switch (changes & SPECIALS_MASK) {
00545   case SPECIAL_I:
00546     {
00547       u32_t i = ppp_ntohs(IPH_LEN(&cs->cs_ip)) - cs->cs_hlen;
00548       /* some compilers can't nest inline assembler.. */
00549       tmp = ppp_ntohl(th->ackno) + i;
00550       th->ackno = ppp_htonl(tmp);
00551       tmp = ppp_ntohl(th->seqno) + i;
00552       th->seqno = ppp_htonl(tmp);
00553     }
00554     break;
00555 
00556   case SPECIAL_D:
00557     /* some compilers can't nest inline assembler.. */
00558     tmp = ppp_ntohl(th->seqno) + ppp_ntohs(IPH_LEN(&cs->cs_ip)) - cs->cs_hlen;
00559     th->seqno = ppp_htonl(tmp);
00560     break;
00561 
00562   default:
00563     if (changes & NEW_U) {
00564       TCPH_SET_FLAG(th, TCP_URG);
00565       DECODEU(th->urgp);
00566     } else {
00567       TCPH_UNSET_FLAG(th, TCP_URG);
00568     }
00569     if (changes & NEW_W) {
00570       DECODES(th->wnd);
00571     }
00572     if (changes & NEW_A) {
00573       DECODEL(th->ackno);
00574     }
00575     if (changes & NEW_S) {
00576       DECODEL(th->seqno);
00577     }
00578     break;
00579   }
00580   if (changes & NEW_I) {
00581     DECODES(cs->cs_ip._id);
00582   } else {
00583     IPH_ID_SET(&cs->cs_ip, ppp_ntohs(IPH_ID(&cs->cs_ip)) + 1);
00584     IPH_ID_SET(&cs->cs_ip, ppp_htons(IPH_ID(&cs->cs_ip)));
00585   }
00586 
00587   /*
00588    * At this point, cp points to the first byte of data in the
00589    * packet.  Fill in the IP total length and update the IP
00590    * header checksum.
00591    */
00592   vjlen = (u16_t)(cp - (u8_t*)n0->payload);
00593   if (n0->len < vjlen) {
00594     /*
00595      * We must have dropped some characters (crc should detect
00596      * this but the old slip framing won't)
00597      */
00598     PPPDEBUG(LOG_INFO, ("vj_uncompress_tcp: head buffer %d too short %d\n",
00599           n0->len, vjlen));
00600     goto bad;
00601   }
00602 
00603 #if BYTE_ORDER == LITTLE_ENDIAN
00604   tmp = n0->tot_len - vjlen + cs->cs_hlen;
00605   IPH_LEN_SET(&cs->cs_ip, ppp_htons((u16_t)tmp));
00606 #else
00607   IPH_LEN_SET(&cs->cs_ip, ppp_htons(n0->tot_len - vjlen + cs->cs_hlen));
00608 #endif
00609 
00610   /* recompute the ip header checksum */
00611   bp = (struct vj_u16_t*) &cs->cs_ip;
00612   IPH_CHKSUM_SET(&cs->cs_ip, 0);
00613   for (tmp = 0; hlen > 0; hlen -= 2) {
00614     tmp += (*bp++).v;
00615   }
00616   tmp = (tmp & 0xffff) + (tmp >> 16);
00617   tmp = (tmp & 0xffff) + (tmp >> 16);
00618   IPH_CHKSUM_SET(&cs->cs_ip,  (u16_t)(~tmp));
00619 
00620   /* Remove the compressed header and prepend the uncompressed header. */
00621   if (pbuf_remove_header(n0, vjlen)) {
00622     /* Can we cope with this failing?  Just assert for now */
00623     PPP_ASSERT("pbuf_remove_header failed\n", 0);
00624     goto bad;
00625   }
00626 
00627   if(PPP_MEM_ALIGN(n0->payload) != n0->payload) {
00628     struct pbuf *np;
00629 
00630 #if IP_FORWARD
00631     /* If IP forwarding is enabled we are using a PBUF_LINK packet type so
00632      * the packet is being allocated with enough header space to be
00633      * forwarded (to Ethernet for example).
00634      */
00635     np = ppp_memory_buffer_allocate(pcb->netif->memory_manager, n0->len + cs->cs_hlen, PPP_BUF_POOL);
00636 #else /* IP_FORWARD */
00637     np = ppp_memory_buffer_allocate(pcb->netif->memory_manager, n0->len + cs->cs_hlen, PPP_BUF_POOL);
00638 #endif /* IP_FORWARD */
00639     if(!np) {
00640       PPPDEBUG(LOG_WARNING, ("vj_uncompress_tcp: realign failed\n"));
00641       goto bad;
00642     }
00643 
00644     if (pbuf_remove_header(np, cs->cs_hlen)) {
00645       /* Can we cope with this failing?  Just assert for now */
00646       PPP_ASSERT("pbuf_remove_header failed\n", 0);
00647       goto bad;
00648     }
00649 
00650     pbuf_take(np, n0->payload, n0->len);
00651 
00652     if(n0->next) {
00653       pbuf_chain(np, n0->next);
00654       pbuf_dechain(n0);
00655     }
00656     ppp_memory_buffer_free(n0);
00657     n0 = np;
00658   }
00659 
00660   if (pbuf_add_header(n0, cs->cs_hlen)) {
00661     struct pbuf *np;
00662 
00663     PPP_ASSERT("vj_uncompress_tcp: cs->cs_hlen <= PBUF_POOL_BUFSIZE", cs->cs_hlen <= PBUF_POOL_BUFSIZE);
00664     np = ppp_memory_buffer_allocate(pcb->netif->memory_manager, cs->cs_hlen, PPP_BUF_POOL);
00665     if(!np) {
00666       PPPDEBUG(LOG_WARNING, ("vj_uncompress_tcp: prepend failed\n"));
00667       goto bad;
00668     }
00669     pbuf_cat(np, n0);
00670     n0 = np;
00671   }
00672   PPP_ASSERT("n0->len >= cs->cs_hlen", n0->len >= cs->cs_hlen);
00673   MEMCPY(n0->payload, &cs->cs_ip, cs->cs_hlen);
00674 
00675   *nb = n0;
00676 
00677   return vjlen;
00678 
00679 bad:
00680   vj_uncompress_err(comp);
00681   return (-1);
00682 }
00683 
00684 #endif /* PPP_SUPPORT && VJ_SUPPORT */