SAMV71 Xplained Ultra Software Package 1.4

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