1195972f6Sopenharmony_ci/*
2195972f6Sopenharmony_ci * Routines to compress and uncompess tcp packets (for transmission
3195972f6Sopenharmony_ci * over low speed serial lines.
4195972f6Sopenharmony_ci *
5195972f6Sopenharmony_ci * Copyright (c) 1989 Regents of the University of California.
6195972f6Sopenharmony_ci * All rights reserved.
7195972f6Sopenharmony_ci *
8195972f6Sopenharmony_ci * Redistribution and use in source and binary forms are permitted
9195972f6Sopenharmony_ci * provided that the above copyright notice and this paragraph are
10195972f6Sopenharmony_ci * duplicated in all such forms and that any documentation,
11195972f6Sopenharmony_ci * advertising materials, and other materials related to such
12195972f6Sopenharmony_ci * distribution and use acknowledge that the software was developed
13195972f6Sopenharmony_ci * by the University of California, Berkeley.  The name of the
14195972f6Sopenharmony_ci * University may not be used to endorse or promote products derived
15195972f6Sopenharmony_ci * from this software without specific prior written permission.
16195972f6Sopenharmony_ci * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17195972f6Sopenharmony_ci * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18195972f6Sopenharmony_ci * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19195972f6Sopenharmony_ci *
20195972f6Sopenharmony_ci * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
21195972f6Sopenharmony_ci *   Initial distribution.
22195972f6Sopenharmony_ci *
23195972f6Sopenharmony_ci * Modified June 1993 by Paul Mackerras, paulus@cs.anu.edu.au,
24195972f6Sopenharmony_ci * so that the entire packet being decompressed doesn't have
25195972f6Sopenharmony_ci * to be in contiguous memory (just the compressed header).
26195972f6Sopenharmony_ci *
27195972f6Sopenharmony_ci * Modified March 1998 by Guy Lancaster, glanca@gesn.com,
28195972f6Sopenharmony_ci * for a 16 bit processor.
29195972f6Sopenharmony_ci */
30195972f6Sopenharmony_ci
31195972f6Sopenharmony_ci#include "netif/ppp/ppp_opts.h"
32195972f6Sopenharmony_ci#if PPP_SUPPORT && VJ_SUPPORT /* don't build if not configured for use in lwipopts.h */
33195972f6Sopenharmony_ci
34195972f6Sopenharmony_ci#include "netif/ppp/ppp_impl.h"
35195972f6Sopenharmony_ci#include "netif/ppp/pppdebug.h"
36195972f6Sopenharmony_ci
37195972f6Sopenharmony_ci#include "netif/ppp/vj.h"
38195972f6Sopenharmony_ci
39195972f6Sopenharmony_ci#include <string.h>
40195972f6Sopenharmony_ci
41195972f6Sopenharmony_ci#if LINK_STATS
42195972f6Sopenharmony_ci#define INCR(counter) ++comp->stats.counter
43195972f6Sopenharmony_ci#else
44195972f6Sopenharmony_ci#define INCR(counter)
45195972f6Sopenharmony_ci#endif
46195972f6Sopenharmony_ci
47195972f6Sopenharmony_civoid
48195972f6Sopenharmony_civj_compress_init(struct vjcompress *comp)
49195972f6Sopenharmony_ci{
50195972f6Sopenharmony_ci  u8_t i;
51195972f6Sopenharmony_ci  struct cstate *tstate = comp->tstate;
52195972f6Sopenharmony_ci
53195972f6Sopenharmony_ci#if MAX_SLOTS == 0
54195972f6Sopenharmony_ci  memset((char *)comp, 0, sizeof(*comp));
55195972f6Sopenharmony_ci#endif
56195972f6Sopenharmony_ci  comp->maxSlotIndex = MAX_SLOTS - 1;
57195972f6Sopenharmony_ci  comp->compressSlot = 0;    /* Disable slot ID compression by default. */
58195972f6Sopenharmony_ci  for (i = MAX_SLOTS - 1; i > 0; --i) {
59195972f6Sopenharmony_ci    tstate[i].cs_id = i;
60195972f6Sopenharmony_ci    tstate[i].cs_next = &tstate[i - 1];
61195972f6Sopenharmony_ci  }
62195972f6Sopenharmony_ci  tstate[0].cs_next = &tstate[MAX_SLOTS - 1];
63195972f6Sopenharmony_ci  tstate[0].cs_id = 0;
64195972f6Sopenharmony_ci  comp->last_cs = &tstate[0];
65195972f6Sopenharmony_ci  comp->last_recv = 255;
66195972f6Sopenharmony_ci  comp->last_xmit = 255;
67195972f6Sopenharmony_ci  comp->flags = VJF_TOSS;
68195972f6Sopenharmony_ci}
69195972f6Sopenharmony_ci
70195972f6Sopenharmony_ci
71195972f6Sopenharmony_ci/* ENCODE encodes a number that is known to be non-zero.  ENCODEZ
72195972f6Sopenharmony_ci * checks for zero (since zero has to be encoded in the long, 3 byte
73195972f6Sopenharmony_ci * form).
74195972f6Sopenharmony_ci */
75195972f6Sopenharmony_ci#define ENCODE(n) { \
76195972f6Sopenharmony_ci  if ((u16_t)(n) >= 256) { \
77195972f6Sopenharmony_ci    *cp++ = 0; \
78195972f6Sopenharmony_ci    cp[1] = (u8_t)(n); \
79195972f6Sopenharmony_ci    cp[0] = (u8_t)((n) >> 8); \
80195972f6Sopenharmony_ci    cp += 2; \
81195972f6Sopenharmony_ci  } else { \
82195972f6Sopenharmony_ci    *cp++ = (u8_t)(n); \
83195972f6Sopenharmony_ci  } \
84195972f6Sopenharmony_ci}
85195972f6Sopenharmony_ci#define ENCODEZ(n) { \
86195972f6Sopenharmony_ci  if ((u16_t)(n) >= 256 || (u16_t)(n) == 0) { \
87195972f6Sopenharmony_ci    *cp++ = 0; \
88195972f6Sopenharmony_ci    cp[1] = (u8_t)(n); \
89195972f6Sopenharmony_ci    cp[0] = (u8_t)((n) >> 8); \
90195972f6Sopenharmony_ci    cp += 2; \
91195972f6Sopenharmony_ci  } else { \
92195972f6Sopenharmony_ci    *cp++ = (u8_t)(n); \
93195972f6Sopenharmony_ci  } \
94195972f6Sopenharmony_ci}
95195972f6Sopenharmony_ci
96195972f6Sopenharmony_ci#define DECODEL(f) { \
97195972f6Sopenharmony_ci  if (*cp == 0) {\
98195972f6Sopenharmony_ci    u32_t tmp_ = lwip_ntohl(f) + ((cp[1] << 8) | cp[2]); \
99195972f6Sopenharmony_ci    (f) = lwip_htonl(tmp_); \
100195972f6Sopenharmony_ci    cp += 3; \
101195972f6Sopenharmony_ci  } else { \
102195972f6Sopenharmony_ci    u32_t tmp_ = lwip_ntohl(f) + (u32_t)*cp++; \
103195972f6Sopenharmony_ci    (f) = lwip_htonl(tmp_); \
104195972f6Sopenharmony_ci  } \
105195972f6Sopenharmony_ci}
106195972f6Sopenharmony_ci
107195972f6Sopenharmony_ci#define DECODES(f) { \
108195972f6Sopenharmony_ci  if (*cp == 0) {\
109195972f6Sopenharmony_ci    u16_t tmp_ = lwip_ntohs(f) + (((u16_t)cp[1] << 8) | cp[2]); \
110195972f6Sopenharmony_ci    (f) = lwip_htons(tmp_); \
111195972f6Sopenharmony_ci    cp += 3; \
112195972f6Sopenharmony_ci  } else { \
113195972f6Sopenharmony_ci    u16_t tmp_ = lwip_ntohs(f) + (u16_t)*cp++; \
114195972f6Sopenharmony_ci    (f) = lwip_htons(tmp_); \
115195972f6Sopenharmony_ci  } \
116195972f6Sopenharmony_ci}
117195972f6Sopenharmony_ci
118195972f6Sopenharmony_ci#define DECODEU(f) { \
119195972f6Sopenharmony_ci  if (*cp == 0) {\
120195972f6Sopenharmony_ci    (f) = lwip_htons(((u16_t)cp[1] << 8) | cp[2]); \
121195972f6Sopenharmony_ci    cp += 3; \
122195972f6Sopenharmony_ci  } else { \
123195972f6Sopenharmony_ci    (f) = lwip_htons((u16_t)*cp++); \
124195972f6Sopenharmony_ci  } \
125195972f6Sopenharmony_ci}
126195972f6Sopenharmony_ci
127195972f6Sopenharmony_ci/* Helper structures for unaligned *u32_t and *u16_t accesses */
128195972f6Sopenharmony_ci#ifdef PACK_STRUCT_USE_INCLUDES
129195972f6Sopenharmony_ci#  include "arch/bpstruct.h"
130195972f6Sopenharmony_ci#endif
131195972f6Sopenharmony_ciPACK_STRUCT_BEGIN
132195972f6Sopenharmony_cistruct vj_u32_t {
133195972f6Sopenharmony_ci  PACK_STRUCT_FIELD(u32_t v);
134195972f6Sopenharmony_ci} PACK_STRUCT_STRUCT;
135195972f6Sopenharmony_ciPACK_STRUCT_END
136195972f6Sopenharmony_ci#ifdef PACK_STRUCT_USE_INCLUDES
137195972f6Sopenharmony_ci#  include "arch/epstruct.h"
138195972f6Sopenharmony_ci#endif
139195972f6Sopenharmony_ci
140195972f6Sopenharmony_ci#ifdef PACK_STRUCT_USE_INCLUDES
141195972f6Sopenharmony_ci#  include "arch/bpstruct.h"
142195972f6Sopenharmony_ci#endif
143195972f6Sopenharmony_ciPACK_STRUCT_BEGIN
144195972f6Sopenharmony_cistruct vj_u16_t {
145195972f6Sopenharmony_ci  PACK_STRUCT_FIELD(u16_t v);
146195972f6Sopenharmony_ci} PACK_STRUCT_STRUCT;
147195972f6Sopenharmony_ciPACK_STRUCT_END
148195972f6Sopenharmony_ci#ifdef PACK_STRUCT_USE_INCLUDES
149195972f6Sopenharmony_ci#  include "arch/epstruct.h"
150195972f6Sopenharmony_ci#endif
151195972f6Sopenharmony_ci
152195972f6Sopenharmony_ci/*
153195972f6Sopenharmony_ci * vj_compress_tcp - Attempt to do Van Jacobson header compression on a
154195972f6Sopenharmony_ci * packet.  This assumes that nb and comp are not null and that the first
155195972f6Sopenharmony_ci * buffer of the chain contains a valid IP header.
156195972f6Sopenharmony_ci * Return the VJ type code indicating whether or not the packet was
157195972f6Sopenharmony_ci * compressed.
158195972f6Sopenharmony_ci */
159195972f6Sopenharmony_ciu8_t
160195972f6Sopenharmony_civj_compress_tcp(struct vjcompress *comp, struct pbuf **pb)
161195972f6Sopenharmony_ci{
162195972f6Sopenharmony_ci  struct pbuf *np = *pb;
163195972f6Sopenharmony_ci  struct ip_hdr *ip = (struct ip_hdr *)np->payload;
164195972f6Sopenharmony_ci  struct cstate *cs = comp->last_cs->cs_next;
165195972f6Sopenharmony_ci  u16_t ilen = IPH_HL(ip);
166195972f6Sopenharmony_ci  u16_t hlen;
167195972f6Sopenharmony_ci  struct tcp_hdr *oth;
168195972f6Sopenharmony_ci  struct tcp_hdr *th;
169195972f6Sopenharmony_ci  u16_t deltaS, deltaA = 0;
170195972f6Sopenharmony_ci  u32_t deltaL;
171195972f6Sopenharmony_ci  u32_t changes = 0;
172195972f6Sopenharmony_ci  u8_t new_seq[16];
173195972f6Sopenharmony_ci  u8_t *cp = new_seq;
174195972f6Sopenharmony_ci
175195972f6Sopenharmony_ci  /*
176195972f6Sopenharmony_ci   * Check that the packet is IP proto TCP.
177195972f6Sopenharmony_ci   */
178195972f6Sopenharmony_ci  if (IPH_PROTO(ip) != IP_PROTO_TCP) {
179195972f6Sopenharmony_ci    return (TYPE_IP);
180195972f6Sopenharmony_ci  }
181195972f6Sopenharmony_ci
182195972f6Sopenharmony_ci  /*
183195972f6Sopenharmony_ci   * Bail if this is an IP fragment or if the TCP packet isn't
184195972f6Sopenharmony_ci   * `compressible' (i.e., ACK isn't set or some other control bit is
185195972f6Sopenharmony_ci   * set).
186195972f6Sopenharmony_ci   */
187195972f6Sopenharmony_ci  if ((IPH_OFFSET(ip) & PP_HTONS(0x3fff)) || np->tot_len < 40) {
188195972f6Sopenharmony_ci    return (TYPE_IP);
189195972f6Sopenharmony_ci  }
190195972f6Sopenharmony_ci  th = (struct tcp_hdr *)&((struct vj_u32_t*)ip)[ilen];
191195972f6Sopenharmony_ci  if ((TCPH_FLAGS(th) & (TCP_SYN|TCP_FIN|TCP_RST|TCP_ACK)) != TCP_ACK) {
192195972f6Sopenharmony_ci    return (TYPE_IP);
193195972f6Sopenharmony_ci  }
194195972f6Sopenharmony_ci
195195972f6Sopenharmony_ci  /* Check that the TCP/IP headers are contained in the first buffer. */
196195972f6Sopenharmony_ci  hlen = ilen + TCPH_HDRLEN(th);
197195972f6Sopenharmony_ci  hlen <<= 2;
198195972f6Sopenharmony_ci  if (np->len < hlen) {
199195972f6Sopenharmony_ci    PPPDEBUG(LOG_INFO, ("vj_compress_tcp: header len %d spans buffers\n", hlen));
200195972f6Sopenharmony_ci    return (TYPE_IP);
201195972f6Sopenharmony_ci  }
202195972f6Sopenharmony_ci
203195972f6Sopenharmony_ci  /* TCP stack requires that we don't change the packet payload, therefore we copy
204195972f6Sopenharmony_ci   * the whole packet before compression. */
205195972f6Sopenharmony_ci  np = pbuf_clone(PBUF_RAW, PBUF_RAM, *pb);
206195972f6Sopenharmony_ci  if (!np) {
207195972f6Sopenharmony_ci    return (TYPE_IP);
208195972f6Sopenharmony_ci  }
209195972f6Sopenharmony_ci
210195972f6Sopenharmony_ci  *pb = np;
211195972f6Sopenharmony_ci  ip = (struct ip_hdr *)np->payload;
212195972f6Sopenharmony_ci
213195972f6Sopenharmony_ci  /*
214195972f6Sopenharmony_ci   * Packet is compressible -- we're going to send either a
215195972f6Sopenharmony_ci   * COMPRESSED_TCP or UNCOMPRESSED_TCP packet.  Either way we need
216195972f6Sopenharmony_ci   * to locate (or create) the connection state.  Special case the
217195972f6Sopenharmony_ci   * most recently used connection since it's most likely to be used
218195972f6Sopenharmony_ci   * again & we don't have to do any reordering if it's used.
219195972f6Sopenharmony_ci   */
220195972f6Sopenharmony_ci  INCR(vjs_packets);
221195972f6Sopenharmony_ci  if (!ip4_addr_cmp(&ip->src, &cs->cs_ip.src)
222195972f6Sopenharmony_ci      || !ip4_addr_cmp(&ip->dest, &cs->cs_ip.dest)
223195972f6Sopenharmony_ci      || (*(struct vj_u32_t*)th).v != (((struct vj_u32_t*)&cs->cs_ip)[IPH_HL(&cs->cs_ip)]).v) {
224195972f6Sopenharmony_ci    /*
225195972f6Sopenharmony_ci     * Wasn't the first -- search for it.
226195972f6Sopenharmony_ci     *
227195972f6Sopenharmony_ci     * States are kept in a circularly linked list with
228195972f6Sopenharmony_ci     * last_cs pointing to the end of the list.  The
229195972f6Sopenharmony_ci     * list is kept in lru order by moving a state to the
230195972f6Sopenharmony_ci     * head of the list whenever it is referenced.  Since
231195972f6Sopenharmony_ci     * the list is short and, empirically, the connection
232195972f6Sopenharmony_ci     * we want is almost always near the front, we locate
233195972f6Sopenharmony_ci     * states via linear search.  If we don't find a state
234195972f6Sopenharmony_ci     * for the datagram, the oldest state is (re-)used.
235195972f6Sopenharmony_ci     */
236195972f6Sopenharmony_ci    struct cstate *lcs;
237195972f6Sopenharmony_ci    struct cstate *lastcs = comp->last_cs;
238195972f6Sopenharmony_ci
239195972f6Sopenharmony_ci    do {
240195972f6Sopenharmony_ci      lcs = cs; cs = cs->cs_next;
241195972f6Sopenharmony_ci      INCR(vjs_searches);
242195972f6Sopenharmony_ci      if (ip4_addr_cmp(&ip->src, &cs->cs_ip.src)
243195972f6Sopenharmony_ci          && ip4_addr_cmp(&ip->dest, &cs->cs_ip.dest)
244195972f6Sopenharmony_ci          && (*(struct vj_u32_t*)th).v == (((struct vj_u32_t*)&cs->cs_ip)[IPH_HL(&cs->cs_ip)]).v) {
245195972f6Sopenharmony_ci        goto found;
246195972f6Sopenharmony_ci      }
247195972f6Sopenharmony_ci    } while (cs != lastcs);
248195972f6Sopenharmony_ci
249195972f6Sopenharmony_ci    /*
250195972f6Sopenharmony_ci     * Didn't find it -- re-use oldest cstate.  Send an
251195972f6Sopenharmony_ci     * uncompressed packet that tells the other side what
252195972f6Sopenharmony_ci     * connection number we're using for this conversation.
253195972f6Sopenharmony_ci     * Note that since the state list is circular, the oldest
254195972f6Sopenharmony_ci     * state points to the newest and we only need to set
255195972f6Sopenharmony_ci     * last_cs to update the lru linkage.
256195972f6Sopenharmony_ci     */
257195972f6Sopenharmony_ci    INCR(vjs_misses);
258195972f6Sopenharmony_ci    comp->last_cs = lcs;
259195972f6Sopenharmony_ci    goto uncompressed;
260195972f6Sopenharmony_ci
261195972f6Sopenharmony_ci    found:
262195972f6Sopenharmony_ci    /*
263195972f6Sopenharmony_ci     * Found it -- move to the front on the connection list.
264195972f6Sopenharmony_ci     */
265195972f6Sopenharmony_ci    if (cs == lastcs) {
266195972f6Sopenharmony_ci      comp->last_cs = lcs;
267195972f6Sopenharmony_ci    } else {
268195972f6Sopenharmony_ci      lcs->cs_next = cs->cs_next;
269195972f6Sopenharmony_ci      cs->cs_next = lastcs->cs_next;
270195972f6Sopenharmony_ci      lastcs->cs_next = cs;
271195972f6Sopenharmony_ci    }
272195972f6Sopenharmony_ci  }
273195972f6Sopenharmony_ci
274195972f6Sopenharmony_ci  oth = (struct tcp_hdr *)&((struct vj_u32_t*)&cs->cs_ip)[ilen];
275195972f6Sopenharmony_ci  deltaS = ilen;
276195972f6Sopenharmony_ci
277195972f6Sopenharmony_ci  /*
278195972f6Sopenharmony_ci   * Make sure that only what we expect to change changed. The first
279195972f6Sopenharmony_ci   * line of the `if' checks the IP protocol version, header length &
280195972f6Sopenharmony_ci   * type of service.  The 2nd line checks the "Don't fragment" bit.
281195972f6Sopenharmony_ci   * The 3rd line checks the time-to-live and protocol (the protocol
282195972f6Sopenharmony_ci   * check is unnecessary but costless).  The 4th line checks the TCP
283195972f6Sopenharmony_ci   * header length.  The 5th line checks IP options, if any.  The 6th
284195972f6Sopenharmony_ci   * line checks TCP options, if any.  If any of these things are
285195972f6Sopenharmony_ci   * different between the previous & current datagram, we send the
286195972f6Sopenharmony_ci   * current datagram `uncompressed'.
287195972f6Sopenharmony_ci   */
288195972f6Sopenharmony_ci  if ((((struct vj_u16_t*)ip)[0]).v != (((struct vj_u16_t*)&cs->cs_ip)[0]).v
289195972f6Sopenharmony_ci      || (((struct vj_u16_t*)ip)[3]).v != (((struct vj_u16_t*)&cs->cs_ip)[3]).v
290195972f6Sopenharmony_ci      || (((struct vj_u16_t*)ip)[4]).v != (((struct vj_u16_t*)&cs->cs_ip)[4]).v
291195972f6Sopenharmony_ci      || TCPH_HDRLEN(th) != TCPH_HDRLEN(oth)
292195972f6Sopenharmony_ci      || (deltaS > 5 && BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2))
293195972f6Sopenharmony_ci      || (TCPH_HDRLEN(th) > 5 && BCMP(th + 1, oth + 1, (TCPH_HDRLEN(th) - 5) << 2))) {
294195972f6Sopenharmony_ci    goto uncompressed;
295195972f6Sopenharmony_ci  }
296195972f6Sopenharmony_ci
297195972f6Sopenharmony_ci  /*
298195972f6Sopenharmony_ci   * Figure out which of the changing fields changed.  The
299195972f6Sopenharmony_ci   * receiver expects changes in the order: urgent, window,
300195972f6Sopenharmony_ci   * ack, seq (the order minimizes the number of temporaries
301195972f6Sopenharmony_ci   * needed in this section of code).
302195972f6Sopenharmony_ci   */
303195972f6Sopenharmony_ci  if (TCPH_FLAGS(th) & TCP_URG) {
304195972f6Sopenharmony_ci    deltaS = lwip_ntohs(th->urgp);
305195972f6Sopenharmony_ci    ENCODEZ(deltaS);
306195972f6Sopenharmony_ci    changes |= NEW_U;
307195972f6Sopenharmony_ci  } else if (th->urgp != oth->urgp) {
308195972f6Sopenharmony_ci    /* argh! URG not set but urp changed -- a sensible
309195972f6Sopenharmony_ci     * implementation should never do this but RFC793
310195972f6Sopenharmony_ci     * doesn't prohibit the change so we have to deal
311195972f6Sopenharmony_ci     * with it. */
312195972f6Sopenharmony_ci    goto uncompressed;
313195972f6Sopenharmony_ci  }
314195972f6Sopenharmony_ci
315195972f6Sopenharmony_ci  if ((deltaS = (u16_t)(lwip_ntohs(th->wnd) - lwip_ntohs(oth->wnd))) != 0) {
316195972f6Sopenharmony_ci    ENCODE(deltaS);
317195972f6Sopenharmony_ci    changes |= NEW_W;
318195972f6Sopenharmony_ci  }
319195972f6Sopenharmony_ci
320195972f6Sopenharmony_ci  if ((deltaL = lwip_ntohl(th->ackno) - lwip_ntohl(oth->ackno)) != 0) {
321195972f6Sopenharmony_ci    if (deltaL > 0xffff) {
322195972f6Sopenharmony_ci      goto uncompressed;
323195972f6Sopenharmony_ci    }
324195972f6Sopenharmony_ci    deltaA = (u16_t)deltaL;
325195972f6Sopenharmony_ci    ENCODE(deltaA);
326195972f6Sopenharmony_ci    changes |= NEW_A;
327195972f6Sopenharmony_ci  }
328195972f6Sopenharmony_ci
329195972f6Sopenharmony_ci  if ((deltaL = lwip_ntohl(th->seqno) - lwip_ntohl(oth->seqno)) != 0) {
330195972f6Sopenharmony_ci    if (deltaL > 0xffff) {
331195972f6Sopenharmony_ci      goto uncompressed;
332195972f6Sopenharmony_ci    }
333195972f6Sopenharmony_ci    deltaS = (u16_t)deltaL;
334195972f6Sopenharmony_ci    ENCODE(deltaS);
335195972f6Sopenharmony_ci    changes |= NEW_S;
336195972f6Sopenharmony_ci  }
337195972f6Sopenharmony_ci
338195972f6Sopenharmony_ci  switch(changes) {
339195972f6Sopenharmony_ci  case 0:
340195972f6Sopenharmony_ci    /*
341195972f6Sopenharmony_ci     * Nothing changed. If this packet contains data and the
342195972f6Sopenharmony_ci     * last one didn't, this is probably a data packet following
343195972f6Sopenharmony_ci     * an ack (normal on an interactive connection) and we send
344195972f6Sopenharmony_ci     * it compressed.  Otherwise it's probably a retransmit,
345195972f6Sopenharmony_ci     * retransmitted ack or window probe.  Send it uncompressed
346195972f6Sopenharmony_ci     * in case the other side missed the compressed version.
347195972f6Sopenharmony_ci     */
348195972f6Sopenharmony_ci    if (IPH_LEN(ip) != IPH_LEN(&cs->cs_ip) &&
349195972f6Sopenharmony_ci      lwip_ntohs(IPH_LEN(&cs->cs_ip)) == hlen) {
350195972f6Sopenharmony_ci      break;
351195972f6Sopenharmony_ci    }
352195972f6Sopenharmony_ci    /* no break */
353195972f6Sopenharmony_ci    /* fall through */
354195972f6Sopenharmony_ci
355195972f6Sopenharmony_ci  case SPECIAL_I:
356195972f6Sopenharmony_ci  case SPECIAL_D:
357195972f6Sopenharmony_ci    /*
358195972f6Sopenharmony_ci     * actual changes match one of our special case encodings --
359195972f6Sopenharmony_ci     * send packet uncompressed.
360195972f6Sopenharmony_ci     */
361195972f6Sopenharmony_ci    goto uncompressed;
362195972f6Sopenharmony_ci
363195972f6Sopenharmony_ci  case NEW_S|NEW_A:
364195972f6Sopenharmony_ci    if (deltaS == deltaA && deltaS == lwip_ntohs(IPH_LEN(&cs->cs_ip)) - hlen) {
365195972f6Sopenharmony_ci      /* special case for echoed terminal traffic */
366195972f6Sopenharmony_ci      changes = SPECIAL_I;
367195972f6Sopenharmony_ci      cp = new_seq;
368195972f6Sopenharmony_ci    }
369195972f6Sopenharmony_ci    break;
370195972f6Sopenharmony_ci
371195972f6Sopenharmony_ci  case NEW_S:
372195972f6Sopenharmony_ci    if (deltaS == lwip_ntohs(IPH_LEN(&cs->cs_ip)) - hlen) {
373195972f6Sopenharmony_ci      /* special case for data xfer */
374195972f6Sopenharmony_ci      changes = SPECIAL_D;
375195972f6Sopenharmony_ci      cp = new_seq;
376195972f6Sopenharmony_ci    }
377195972f6Sopenharmony_ci    break;
378195972f6Sopenharmony_ci  default:
379195972f6Sopenharmony_ci     break;
380195972f6Sopenharmony_ci  }
381195972f6Sopenharmony_ci
382195972f6Sopenharmony_ci  deltaS = (u16_t)(lwip_ntohs(IPH_ID(ip)) - lwip_ntohs(IPH_ID(&cs->cs_ip)));
383195972f6Sopenharmony_ci  if (deltaS != 1) {
384195972f6Sopenharmony_ci    ENCODEZ(deltaS);
385195972f6Sopenharmony_ci    changes |= NEW_I;
386195972f6Sopenharmony_ci  }
387195972f6Sopenharmony_ci  if (TCPH_FLAGS(th) & TCP_PSH) {
388195972f6Sopenharmony_ci    changes |= TCP_PUSH_BIT;
389195972f6Sopenharmony_ci  }
390195972f6Sopenharmony_ci  /*
391195972f6Sopenharmony_ci   * Grab the cksum before we overwrite it below.  Then update our
392195972f6Sopenharmony_ci   * state with this packet's header.
393195972f6Sopenharmony_ci   */
394195972f6Sopenharmony_ci  deltaA = lwip_ntohs(th->chksum);
395195972f6Sopenharmony_ci  MEMCPY(&cs->cs_ip, ip, hlen);
396195972f6Sopenharmony_ci
397195972f6Sopenharmony_ci  /*
398195972f6Sopenharmony_ci   * We want to use the original packet as our compressed packet.
399195972f6Sopenharmony_ci   * (cp - new_seq) is the number of bytes we need for compressed
400195972f6Sopenharmony_ci   * sequence numbers.  In addition we need one byte for the change
401195972f6Sopenharmony_ci   * mask, one for the connection id and two for the tcp checksum.
402195972f6Sopenharmony_ci   * So, (cp - new_seq) + 4 bytes of header are needed.  hlen is how
403195972f6Sopenharmony_ci   * many bytes of the original packet to toss so subtract the two to
404195972f6Sopenharmony_ci   * get the new packet size.
405195972f6Sopenharmony_ci   */
406195972f6Sopenharmony_ci  deltaS = (u16_t)(cp - new_seq);
407195972f6Sopenharmony_ci  if (!comp->compressSlot || comp->last_xmit != cs->cs_id) {
408195972f6Sopenharmony_ci    comp->last_xmit = cs->cs_id;
409195972f6Sopenharmony_ci    hlen -= deltaS + 4;
410195972f6Sopenharmony_ci    if (pbuf_remove_header(np, hlen)){
411195972f6Sopenharmony_ci      /* Can we cope with this failing?  Just assert for now */
412195972f6Sopenharmony_ci      LWIP_ASSERT("pbuf_remove_header failed\n", 0);
413195972f6Sopenharmony_ci    }
414195972f6Sopenharmony_ci    cp = (u8_t*)np->payload;
415195972f6Sopenharmony_ci    *cp++ = (u8_t)(changes | NEW_C);
416195972f6Sopenharmony_ci    *cp++ = cs->cs_id;
417195972f6Sopenharmony_ci  } else {
418195972f6Sopenharmony_ci    hlen -= deltaS + 3;
419195972f6Sopenharmony_ci    if (pbuf_remove_header(np, hlen)) {
420195972f6Sopenharmony_ci      /* Can we cope with this failing?  Just assert for now */
421195972f6Sopenharmony_ci      LWIP_ASSERT("pbuf_remove_header failed\n", 0);
422195972f6Sopenharmony_ci    }
423195972f6Sopenharmony_ci    cp = (u8_t*)np->payload;
424195972f6Sopenharmony_ci    *cp++ = (u8_t)changes;
425195972f6Sopenharmony_ci  }
426195972f6Sopenharmony_ci  *cp++ = (u8_t)(deltaA >> 8);
427195972f6Sopenharmony_ci  *cp++ = (u8_t)deltaA;
428195972f6Sopenharmony_ci  MEMCPY(cp, new_seq, deltaS);
429195972f6Sopenharmony_ci  INCR(vjs_compressed);
430195972f6Sopenharmony_ci  return (TYPE_COMPRESSED_TCP);
431195972f6Sopenharmony_ci
432195972f6Sopenharmony_ci  /*
433195972f6Sopenharmony_ci   * Update connection state cs & send uncompressed packet (that is,
434195972f6Sopenharmony_ci   * a regular ip/tcp packet but with the 'conversation id' we hope
435195972f6Sopenharmony_ci   * to use on future compressed packets in the protocol field).
436195972f6Sopenharmony_ci   */
437195972f6Sopenharmony_ciuncompressed:
438195972f6Sopenharmony_ci  MEMCPY(&cs->cs_ip, ip, hlen);
439195972f6Sopenharmony_ci  IPH_PROTO_SET(ip, cs->cs_id);
440195972f6Sopenharmony_ci  comp->last_xmit = cs->cs_id;
441195972f6Sopenharmony_ci  return (TYPE_UNCOMPRESSED_TCP);
442195972f6Sopenharmony_ci}
443195972f6Sopenharmony_ci
444195972f6Sopenharmony_ci/*
445195972f6Sopenharmony_ci * Called when we may have missed a packet.
446195972f6Sopenharmony_ci */
447195972f6Sopenharmony_civoid
448195972f6Sopenharmony_civj_uncompress_err(struct vjcompress *comp)
449195972f6Sopenharmony_ci{
450195972f6Sopenharmony_ci  comp->flags |= VJF_TOSS;
451195972f6Sopenharmony_ci  INCR(vjs_errorin);
452195972f6Sopenharmony_ci}
453195972f6Sopenharmony_ci
454195972f6Sopenharmony_ci/*
455195972f6Sopenharmony_ci * "Uncompress" a packet of type TYPE_UNCOMPRESSED_TCP.
456195972f6Sopenharmony_ci * Return 0 on success, -1 on failure.
457195972f6Sopenharmony_ci */
458195972f6Sopenharmony_ciint
459195972f6Sopenharmony_civj_uncompress_uncomp(struct pbuf *nb, struct vjcompress *comp)
460195972f6Sopenharmony_ci{
461195972f6Sopenharmony_ci  u32_t hlen;
462195972f6Sopenharmony_ci  struct cstate *cs;
463195972f6Sopenharmony_ci  struct ip_hdr *ip;
464195972f6Sopenharmony_ci
465195972f6Sopenharmony_ci  ip = (struct ip_hdr *)nb->payload;
466195972f6Sopenharmony_ci  hlen = IPH_HL(ip) << 2;
467195972f6Sopenharmony_ci  if (IPH_PROTO(ip) >= MAX_SLOTS
468195972f6Sopenharmony_ci      || hlen + sizeof(struct tcp_hdr) > nb->len
469195972f6Sopenharmony_ci      || (hlen += TCPH_HDRLEN_BYTES((struct tcp_hdr *)&((char *)ip)[hlen]))
470195972f6Sopenharmony_ci          > nb->len
471195972f6Sopenharmony_ci      || hlen > MAX_HDR) {
472195972f6Sopenharmony_ci    PPPDEBUG(LOG_INFO, ("vj_uncompress_uncomp: bad cid=%d, hlen=%d buflen=%d\n",
473195972f6Sopenharmony_ci      IPH_PROTO(ip), hlen, nb->len));
474195972f6Sopenharmony_ci    vj_uncompress_err(comp);
475195972f6Sopenharmony_ci    return -1;
476195972f6Sopenharmony_ci  }
477195972f6Sopenharmony_ci  cs = &comp->rstate[comp->last_recv = IPH_PROTO(ip)];
478195972f6Sopenharmony_ci  comp->flags &=~ VJF_TOSS;
479195972f6Sopenharmony_ci  IPH_PROTO_SET(ip, IP_PROTO_TCP);
480195972f6Sopenharmony_ci  /* copy from/to bigger buffers checked above instead of cs->cs_ip and ip
481195972f6Sopenharmony_ci     just to help static code analysis to see this is correct ;-) */
482195972f6Sopenharmony_ci  MEMCPY(&cs->cs_hdr, nb->payload, hlen);
483195972f6Sopenharmony_ci  cs->cs_hlen = (u16_t)hlen;
484195972f6Sopenharmony_ci  INCR(vjs_uncompressedin);
485195972f6Sopenharmony_ci  return 0;
486195972f6Sopenharmony_ci}
487195972f6Sopenharmony_ci
488195972f6Sopenharmony_ci/*
489195972f6Sopenharmony_ci * Uncompress a packet of type TYPE_COMPRESSED_TCP.
490195972f6Sopenharmony_ci * The packet is composed of a buffer chain and the first buffer
491195972f6Sopenharmony_ci * must contain an accurate chain length.
492195972f6Sopenharmony_ci * The first buffer must include the entire compressed TCP/IP header.
493195972f6Sopenharmony_ci * This procedure replaces the compressed header with the uncompressed
494195972f6Sopenharmony_ci * header and returns the length of the VJ header.
495195972f6Sopenharmony_ci */
496195972f6Sopenharmony_ciint
497195972f6Sopenharmony_civj_uncompress_tcp(struct pbuf **nb, struct vjcompress *comp)
498195972f6Sopenharmony_ci{
499195972f6Sopenharmony_ci  u8_t *cp;
500195972f6Sopenharmony_ci  struct tcp_hdr *th;
501195972f6Sopenharmony_ci  struct cstate *cs;
502195972f6Sopenharmony_ci  struct vj_u16_t *bp;
503195972f6Sopenharmony_ci  struct pbuf *n0 = *nb;
504195972f6Sopenharmony_ci  u32_t tmp;
505195972f6Sopenharmony_ci  u32_t vjlen, hlen, changes;
506195972f6Sopenharmony_ci
507195972f6Sopenharmony_ci  INCR(vjs_compressedin);
508195972f6Sopenharmony_ci  cp = (u8_t*)n0->payload;
509195972f6Sopenharmony_ci  changes = *cp++;
510195972f6Sopenharmony_ci  if (changes & NEW_C) {
511195972f6Sopenharmony_ci    /*
512195972f6Sopenharmony_ci     * Make sure the state index is in range, then grab the state.
513195972f6Sopenharmony_ci     * If we have a good state index, clear the 'discard' flag.
514195972f6Sopenharmony_ci     */
515195972f6Sopenharmony_ci    if (*cp >= MAX_SLOTS) {
516195972f6Sopenharmony_ci      PPPDEBUG(LOG_INFO, ("vj_uncompress_tcp: bad cid=%d\n", *cp));
517195972f6Sopenharmony_ci      goto bad;
518195972f6Sopenharmony_ci    }
519195972f6Sopenharmony_ci
520195972f6Sopenharmony_ci    comp->flags &=~ VJF_TOSS;
521195972f6Sopenharmony_ci    comp->last_recv = *cp++;
522195972f6Sopenharmony_ci  } else {
523195972f6Sopenharmony_ci    /*
524195972f6Sopenharmony_ci     * this packet has an implicit state index.  If we've
525195972f6Sopenharmony_ci     * had a line error since the last time we got an
526195972f6Sopenharmony_ci     * explicit state index, we have to toss the packet.
527195972f6Sopenharmony_ci     */
528195972f6Sopenharmony_ci    if (comp->flags & VJF_TOSS) {
529195972f6Sopenharmony_ci      PPPDEBUG(LOG_INFO, ("vj_uncompress_tcp: tossing\n"));
530195972f6Sopenharmony_ci      INCR(vjs_tossed);
531195972f6Sopenharmony_ci      return (-1);
532195972f6Sopenharmony_ci    }
533195972f6Sopenharmony_ci  }
534195972f6Sopenharmony_ci  cs = &comp->rstate[comp->last_recv];
535195972f6Sopenharmony_ci  hlen = IPH_HL(&cs->cs_ip) << 2;
536195972f6Sopenharmony_ci  th = (struct tcp_hdr *)&((u8_t*)&cs->cs_ip)[hlen];
537195972f6Sopenharmony_ci  th->chksum = lwip_htons((*cp << 8) | cp[1]);
538195972f6Sopenharmony_ci  cp += 2;
539195972f6Sopenharmony_ci  if (changes & TCP_PUSH_BIT) {
540195972f6Sopenharmony_ci    TCPH_SET_FLAG(th, TCP_PSH);
541195972f6Sopenharmony_ci  } else {
542195972f6Sopenharmony_ci    TCPH_UNSET_FLAG(th, TCP_PSH);
543195972f6Sopenharmony_ci  }
544195972f6Sopenharmony_ci
545195972f6Sopenharmony_ci  switch (changes & SPECIALS_MASK) {
546195972f6Sopenharmony_ci  case SPECIAL_I:
547195972f6Sopenharmony_ci    {
548195972f6Sopenharmony_ci      u32_t i = lwip_ntohs(IPH_LEN(&cs->cs_ip)) - cs->cs_hlen;
549195972f6Sopenharmony_ci      /* some compilers can't nest inline assembler.. */
550195972f6Sopenharmony_ci      tmp = lwip_ntohl(th->ackno) + i;
551195972f6Sopenharmony_ci      th->ackno = lwip_htonl(tmp);
552195972f6Sopenharmony_ci      tmp = lwip_ntohl(th->seqno) + i;
553195972f6Sopenharmony_ci      th->seqno = lwip_htonl(tmp);
554195972f6Sopenharmony_ci    }
555195972f6Sopenharmony_ci    break;
556195972f6Sopenharmony_ci
557195972f6Sopenharmony_ci  case SPECIAL_D:
558195972f6Sopenharmony_ci    /* some compilers can't nest inline assembler.. */
559195972f6Sopenharmony_ci    tmp = lwip_ntohl(th->seqno) + lwip_ntohs(IPH_LEN(&cs->cs_ip)) - cs->cs_hlen;
560195972f6Sopenharmony_ci    th->seqno = lwip_htonl(tmp);
561195972f6Sopenharmony_ci    break;
562195972f6Sopenharmony_ci
563195972f6Sopenharmony_ci  default:
564195972f6Sopenharmony_ci    if (changes & NEW_U) {
565195972f6Sopenharmony_ci      TCPH_SET_FLAG(th, TCP_URG);
566195972f6Sopenharmony_ci      DECODEU(th->urgp);
567195972f6Sopenharmony_ci    } else {
568195972f6Sopenharmony_ci      TCPH_UNSET_FLAG(th, TCP_URG);
569195972f6Sopenharmony_ci    }
570195972f6Sopenharmony_ci    if (changes & NEW_W) {
571195972f6Sopenharmony_ci      DECODES(th->wnd);
572195972f6Sopenharmony_ci    }
573195972f6Sopenharmony_ci    if (changes & NEW_A) {
574195972f6Sopenharmony_ci      DECODEL(th->ackno);
575195972f6Sopenharmony_ci    }
576195972f6Sopenharmony_ci    if (changes & NEW_S) {
577195972f6Sopenharmony_ci      DECODEL(th->seqno);
578195972f6Sopenharmony_ci    }
579195972f6Sopenharmony_ci    break;
580195972f6Sopenharmony_ci  }
581195972f6Sopenharmony_ci  if (changes & NEW_I) {
582195972f6Sopenharmony_ci    DECODES(cs->cs_ip._id);
583195972f6Sopenharmony_ci  } else {
584195972f6Sopenharmony_ci    IPH_ID_SET(&cs->cs_ip, lwip_ntohs(IPH_ID(&cs->cs_ip)) + 1);
585195972f6Sopenharmony_ci    IPH_ID_SET(&cs->cs_ip, lwip_htons(IPH_ID(&cs->cs_ip)));
586195972f6Sopenharmony_ci  }
587195972f6Sopenharmony_ci
588195972f6Sopenharmony_ci  /*
589195972f6Sopenharmony_ci   * At this point, cp points to the first byte of data in the
590195972f6Sopenharmony_ci   * packet.  Fill in the IP total length and update the IP
591195972f6Sopenharmony_ci   * header checksum.
592195972f6Sopenharmony_ci   */
593195972f6Sopenharmony_ci  vjlen = (u16_t)(cp - (u8_t*)n0->payload);
594195972f6Sopenharmony_ci  if (n0->len < vjlen) {
595195972f6Sopenharmony_ci    /*
596195972f6Sopenharmony_ci     * We must have dropped some characters (crc should detect
597195972f6Sopenharmony_ci     * this but the old slip framing won't)
598195972f6Sopenharmony_ci     */
599195972f6Sopenharmony_ci    PPPDEBUG(LOG_INFO, ("vj_uncompress_tcp: head buffer %d too short %d\n",
600195972f6Sopenharmony_ci          n0->len, vjlen));
601195972f6Sopenharmony_ci    goto bad;
602195972f6Sopenharmony_ci  }
603195972f6Sopenharmony_ci
604195972f6Sopenharmony_ci#if BYTE_ORDER == LITTLE_ENDIAN
605195972f6Sopenharmony_ci  tmp = n0->tot_len - vjlen + cs->cs_hlen;
606195972f6Sopenharmony_ci  IPH_LEN_SET(&cs->cs_ip, lwip_htons((u16_t)tmp));
607195972f6Sopenharmony_ci#else
608195972f6Sopenharmony_ci  IPH_LEN_SET(&cs->cs_ip, lwip_htons(n0->tot_len - vjlen + cs->cs_hlen));
609195972f6Sopenharmony_ci#endif
610195972f6Sopenharmony_ci
611195972f6Sopenharmony_ci  /* recompute the ip header checksum */
612195972f6Sopenharmony_ci  bp = (struct vj_u16_t*) &cs->cs_ip;
613195972f6Sopenharmony_ci  IPH_CHKSUM_SET(&cs->cs_ip, 0);
614195972f6Sopenharmony_ci  for (tmp = 0; hlen > 0; hlen -= 2) {
615195972f6Sopenharmony_ci    tmp += (*bp++).v;
616195972f6Sopenharmony_ci  }
617195972f6Sopenharmony_ci  tmp = (tmp & 0xffff) + (tmp >> 16);
618195972f6Sopenharmony_ci  tmp = (tmp & 0xffff) + (tmp >> 16);
619195972f6Sopenharmony_ci  IPH_CHKSUM_SET(&cs->cs_ip,  (u16_t)(~tmp));
620195972f6Sopenharmony_ci
621195972f6Sopenharmony_ci  /* Remove the compressed header and prepend the uncompressed header. */
622195972f6Sopenharmony_ci  if (pbuf_remove_header(n0, vjlen)) {
623195972f6Sopenharmony_ci    /* Can we cope with this failing?  Just assert for now */
624195972f6Sopenharmony_ci    LWIP_ASSERT("pbuf_remove_header failed\n", 0);
625195972f6Sopenharmony_ci    goto bad;
626195972f6Sopenharmony_ci  }
627195972f6Sopenharmony_ci
628195972f6Sopenharmony_ci  if(LWIP_MEM_ALIGN(n0->payload) != n0->payload) {
629195972f6Sopenharmony_ci    struct pbuf *np;
630195972f6Sopenharmony_ci
631195972f6Sopenharmony_ci#if IP_FORWARD
632195972f6Sopenharmony_ci    /* If IP forwarding is enabled we are using a PBUF_LINK packet type so
633195972f6Sopenharmony_ci     * the packet is being allocated with enough header space to be
634195972f6Sopenharmony_ci     * forwarded (to Ethernet for example).
635195972f6Sopenharmony_ci     */
636195972f6Sopenharmony_ci    np = pbuf_alloc(PBUF_LINK, n0->len + cs->cs_hlen, PBUF_POOL);
637195972f6Sopenharmony_ci#else /* IP_FORWARD */
638195972f6Sopenharmony_ci    np = pbuf_alloc(PBUF_RAW, n0->len + cs->cs_hlen, PBUF_POOL);
639195972f6Sopenharmony_ci#endif /* IP_FORWARD */
640195972f6Sopenharmony_ci    if(!np) {
641195972f6Sopenharmony_ci      PPPDEBUG(LOG_WARNING, ("vj_uncompress_tcp: realign failed\n"));
642195972f6Sopenharmony_ci      goto bad;
643195972f6Sopenharmony_ci    }
644195972f6Sopenharmony_ci
645195972f6Sopenharmony_ci    if (pbuf_remove_header(np, cs->cs_hlen)) {
646195972f6Sopenharmony_ci      /* Can we cope with this failing?  Just assert for now */
647195972f6Sopenharmony_ci      LWIP_ASSERT("pbuf_remove_header failed\n", 0);
648195972f6Sopenharmony_ci      goto bad;
649195972f6Sopenharmony_ci    }
650195972f6Sopenharmony_ci
651195972f6Sopenharmony_ci    pbuf_take(np, n0->payload, n0->len);
652195972f6Sopenharmony_ci
653195972f6Sopenharmony_ci    if(n0->next) {
654195972f6Sopenharmony_ci      pbuf_chain(np, n0->next);
655195972f6Sopenharmony_ci      pbuf_dechain(n0);
656195972f6Sopenharmony_ci    }
657195972f6Sopenharmony_ci    pbuf_free(n0);
658195972f6Sopenharmony_ci    n0 = np;
659195972f6Sopenharmony_ci  }
660195972f6Sopenharmony_ci
661195972f6Sopenharmony_ci  if (pbuf_add_header(n0, cs->cs_hlen)) {
662195972f6Sopenharmony_ci    struct pbuf *np;
663195972f6Sopenharmony_ci
664195972f6Sopenharmony_ci    LWIP_ASSERT("vj_uncompress_tcp: cs->cs_hlen <= PBUF_POOL_BUFSIZE", cs->cs_hlen <= PBUF_POOL_BUFSIZE);
665195972f6Sopenharmony_ci    np = pbuf_alloc(PBUF_RAW, cs->cs_hlen, PBUF_POOL);
666195972f6Sopenharmony_ci    if(!np) {
667195972f6Sopenharmony_ci      PPPDEBUG(LOG_WARNING, ("vj_uncompress_tcp: prepend failed\n"));
668195972f6Sopenharmony_ci      goto bad;
669195972f6Sopenharmony_ci    }
670195972f6Sopenharmony_ci    pbuf_cat(np, n0);
671195972f6Sopenharmony_ci    n0 = np;
672195972f6Sopenharmony_ci  }
673195972f6Sopenharmony_ci  LWIP_ASSERT("n0->len >= cs->cs_hlen", n0->len >= cs->cs_hlen);
674195972f6Sopenharmony_ci  MEMCPY(n0->payload, &cs->cs_ip, cs->cs_hlen);
675195972f6Sopenharmony_ci
676195972f6Sopenharmony_ci  *nb = n0;
677195972f6Sopenharmony_ci
678195972f6Sopenharmony_ci  return vjlen;
679195972f6Sopenharmony_ci
680195972f6Sopenharmony_cibad:
681195972f6Sopenharmony_ci  vj_uncompress_err(comp);
682195972f6Sopenharmony_ci  return (-1);
683195972f6Sopenharmony_ci}
684195972f6Sopenharmony_ci
685195972f6Sopenharmony_ci#endif /* PPP_SUPPORT && VJ_SUPPORT */
686