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