NetServices Stack source

Dependents:   HelloWorld ServoInterfaceBoardExample1 4180_Lab4

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