Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


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