1/**
2 * @file
3 * Network Point to Point Protocol over Serial file.
4 *
5 */
6
7/*
8 * Redistribution and use in source and binary forms, with or without modification,
9 * are permitted provided that the following conditions are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright notice,
12 *    this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright notice,
14 *    this list of conditions and the following disclaimer in the documentation
15 *    and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 *    derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
20 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
22 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
24 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
28 * OF SUCH DAMAGE.
29 *
30 * This file is part of the lwIP TCP/IP stack.
31 *
32 */
33
34#include "netif/ppp/ppp_opts.h"
35#if PPP_SUPPORT && PPPOS_SUPPORT /* don't build if not configured for use in lwipopts.h */
36
37#include <string.h>
38
39#include "lwip/arch.h"
40#include "lwip/err.h"
41#include "lwip/pbuf.h"
42#include "lwip/sys.h"
43#include "lwip/memp.h"
44#include "lwip/netif.h"
45#include "lwip/snmp.h"
46#include "lwip/priv/tcpip_priv.h"
47#include "lwip/api.h"
48#include "lwip/ip4.h" /* for ip4_input() */
49
50#include "netif/ppp/ppp_impl.h"
51#include "netif/ppp/pppos.h"
52#include "netif/ppp/vj.h"
53
54/* Memory pool */
55LWIP_MEMPOOL_DECLARE(PPPOS_PCB, MEMP_NUM_PPPOS_INTERFACES, sizeof(pppos_pcb), "PPPOS_PCB")
56
57/* callbacks called from PPP core */
58static err_t pppos_write(ppp_pcb *ppp, void *ctx, struct pbuf *p);
59static err_t pppos_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *pb, u16_t protocol);
60static void pppos_connect(ppp_pcb *ppp, void *ctx);
61#if PPP_SERVER
62static void pppos_listen(ppp_pcb *ppp, void *ctx);
63#endif /* PPP_SERVER */
64static void pppos_disconnect(ppp_pcb *ppp, void *ctx);
65static err_t pppos_destroy(ppp_pcb *ppp, void *ctx);
66static void pppos_send_config(ppp_pcb *ppp, void *ctx, u32_t accm, int pcomp, int accomp);
67static void pppos_recv_config(ppp_pcb *ppp, void *ctx, u32_t accm, int pcomp, int accomp);
68
69/* Prototypes for procedures local to this file. */
70#if PPP_INPROC_IRQ_SAFE
71static void pppos_input_callback(void *arg);
72#endif /* PPP_INPROC_IRQ_SAFE */
73static void pppos_input_free_current_packet(pppos_pcb *pppos);
74static void pppos_input_drop(pppos_pcb *pppos);
75static err_t pppos_output_append(pppos_pcb *pppos, err_t err, struct pbuf *nb, u8_t c, u8_t accm, u16_t *fcs);
76static err_t pppos_output_last(pppos_pcb *pppos, err_t err, struct pbuf *nb, u16_t *fcs);
77
78/* Callbacks structure for PPP core */
79static const struct link_callbacks pppos_callbacks = {
80  pppos_connect,
81#if PPP_SERVER
82  pppos_listen,
83#endif /* PPP_SERVER */
84  pppos_disconnect,
85  pppos_destroy,
86  pppos_write,
87  pppos_netif_output,
88  pppos_send_config,
89  pppos_recv_config
90};
91
92/* PPP's Asynchronous-Control-Character-Map.  The mask array is used
93 * to select the specific bit for a character. */
94#define ESCAPE_P(accm, c) ((accm)[(c) >> 3] & 1 << (c & 0x07))
95
96#if PPP_FCS_TABLE
97/*
98 * FCS lookup table as calculated by genfcstab.
99 */
100static const u16_t fcstab[256] = {
101  0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
102  0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
103  0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
104  0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
105  0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
106  0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
107  0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
108  0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
109  0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
110  0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
111  0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
112  0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
113  0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
114  0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
115  0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
116  0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
117  0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
118  0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
119  0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
120  0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
121  0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
122  0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
123  0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
124  0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
125  0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
126  0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
127  0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
128  0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
129  0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
130  0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
131  0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
132  0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
133};
134#define PPP_FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
135#else /* PPP_FCS_TABLE */
136/* The HDLC polynomial: X**0 + X**5 + X**12 + X**16 (0x8408) */
137#define PPP_FCS_POLYNOMIAL 0x8408
138static u16_t
139ppp_get_fcs(u8_t byte)
140{
141  unsigned int octet;
142  int bit;
143  octet = byte;
144  for (bit = 8; bit-- > 0; ) {
145    octet = (octet & 0x01) ? ((octet >> 1) ^ PPP_FCS_POLYNOMIAL) : (octet >> 1);
146  }
147  return octet & 0xffff;
148}
149#define PPP_FCS(fcs, c) (((fcs) >> 8) ^ ppp_get_fcs(((fcs) ^ (c)) & 0xff))
150#endif /* PPP_FCS_TABLE */
151
152/*
153 * Values for FCS calculations.
154 */
155#define PPP_INITFCS     0xffff  /* Initial FCS value */
156#define PPP_GOODFCS     0xf0b8  /* Good final FCS value */
157
158#if PPP_INPROC_IRQ_SAFE
159#define PPPOS_DECL_PROTECT(lev) SYS_ARCH_DECL_PROTECT(lev)
160#define PPPOS_PROTECT(lev) SYS_ARCH_PROTECT(lev)
161#define PPPOS_UNPROTECT(lev) SYS_ARCH_UNPROTECT(lev)
162#else
163#define PPPOS_DECL_PROTECT(lev)
164#define PPPOS_PROTECT(lev)
165#define PPPOS_UNPROTECT(lev)
166#endif /* PPP_INPROC_IRQ_SAFE */
167
168
169/*
170 * Create a new PPP connection using the given serial I/O device.
171 *
172 * Return 0 on success, an error code on failure.
173 */
174ppp_pcb *pppos_create(struct netif *pppif, pppos_output_cb_fn output_cb,
175       ppp_link_status_cb_fn link_status_cb, void *ctx_cb)
176{
177  pppos_pcb *pppos;
178  ppp_pcb *ppp;
179
180  pppos = (pppos_pcb *)LWIP_MEMPOOL_ALLOC(PPPOS_PCB);
181  if (pppos == NULL) {
182    return NULL;
183  }
184
185  ppp = ppp_new(pppif, &pppos_callbacks, pppos, link_status_cb, ctx_cb);
186  if (ppp == NULL) {
187    LWIP_MEMPOOL_FREE(PPPOS_PCB, pppos);
188    return NULL;
189  }
190
191  memset(pppos, 0, sizeof(pppos_pcb));
192  pppos->ppp = ppp;
193  pppos->output_cb = output_cb;
194  return ppp;
195}
196
197/* Called by PPP core */
198static err_t
199pppos_write(ppp_pcb *ppp, void *ctx, struct pbuf *p)
200{
201  pppos_pcb *pppos = (pppos_pcb *)ctx;
202  u8_t *s;
203  struct pbuf *nb;
204  u16_t n;
205  u16_t fcs_out;
206  err_t err;
207  LWIP_UNUSED_ARG(ppp);
208
209  /* Grab an output buffer. */
210  nb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
211  if (nb == NULL) {
212    PPPDEBUG(LOG_WARNING, ("pppos_write[%d]: alloc fail\n", ppp->netif->num));
213    LINK_STATS_INC(link.memerr);
214    LINK_STATS_INC(link.drop);
215    MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards);
216    pbuf_free(p);
217    return ERR_MEM;
218  }
219
220  /* If the link has been idle, we'll send a fresh flag character to
221   * flush any noise. */
222  err = ERR_OK;
223  if ((sys_now() - pppos->last_xmit) >= PPP_MAXIDLEFLAG) {
224    err = pppos_output_append(pppos, err,  nb, PPP_FLAG, 0, NULL);
225  }
226
227  /* Load output buffer. */
228  fcs_out = PPP_INITFCS;
229  s = (u8_t*)p->payload;
230  n = p->len;
231  while (n-- > 0) {
232    err = pppos_output_append(pppos, err,  nb, *s++, 1, &fcs_out);
233  }
234
235  err = pppos_output_last(pppos, err, nb, &fcs_out);
236  if (err == ERR_OK) {
237    PPPDEBUG(LOG_INFO, ("pppos_write[%d]: len=%d\n", ppp->netif->num, p->len));
238  } else {
239    PPPDEBUG(LOG_WARNING, ("pppos_write[%d]: output failed len=%d\n", ppp->netif->num, p->len));
240  }
241  pbuf_free(p);
242  return err;
243}
244
245/* Called by PPP core */
246static err_t
247pppos_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *pb, u16_t protocol)
248{
249  pppos_pcb *pppos = (pppos_pcb *)ctx;
250  struct pbuf *nb, *p;
251  u16_t fcs_out;
252  err_t err;
253  LWIP_UNUSED_ARG(ppp);
254
255  /* Grab an output buffer. */
256  nb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
257  if (nb == NULL) {
258    PPPDEBUG(LOG_WARNING, ("pppos_netif_output[%d]: alloc fail\n", ppp->netif->num));
259    LINK_STATS_INC(link.memerr);
260    LINK_STATS_INC(link.drop);
261    MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards);
262    return ERR_MEM;
263  }
264
265  /* If the link has been idle, we'll send a fresh flag character to
266   * flush any noise. */
267  err = ERR_OK;
268  if ((sys_now() - pppos->last_xmit) >= PPP_MAXIDLEFLAG) {
269    err = pppos_output_append(pppos, err,  nb, PPP_FLAG, 0, NULL);
270  }
271
272  fcs_out = PPP_INITFCS;
273  if (!pppos->accomp) {
274    err = pppos_output_append(pppos, err,  nb, PPP_ALLSTATIONS, 1, &fcs_out);
275    err = pppos_output_append(pppos, err,  nb, PPP_UI, 1, &fcs_out);
276  }
277  if (!pppos->pcomp || protocol > 0xFF) {
278    err = pppos_output_append(pppos, err,  nb, (protocol >> 8) & 0xFF, 1, &fcs_out);
279  }
280  err = pppos_output_append(pppos, err,  nb, protocol & 0xFF, 1, &fcs_out);
281
282  /* Load packet. */
283  for(p = pb; p; p = p->next) {
284    u16_t n = p->len;
285    u8_t *s = (u8_t*)p->payload;
286
287    while (n-- > 0) {
288      err = pppos_output_append(pppos, err,  nb, *s++, 1, &fcs_out);
289    }
290  }
291
292  err = pppos_output_last(pppos, err, nb, &fcs_out);
293  if (err == ERR_OK) {
294    PPPDEBUG(LOG_INFO, ("pppos_netif_output[%d]: proto=0x%"X16_F", len = %d\n", ppp->netif->num, protocol, pb->tot_len));
295  } else {
296    PPPDEBUG(LOG_WARNING, ("pppos_netif_output[%d]: output failed proto=0x%"X16_F", len = %d\n", ppp->netif->num, protocol, pb->tot_len));
297  }
298  return err;
299}
300
301static void
302pppos_connect(ppp_pcb *ppp, void *ctx)
303{
304  pppos_pcb *pppos = (pppos_pcb *)ctx;
305  PPPOS_DECL_PROTECT(lev);
306
307#if PPP_INPROC_IRQ_SAFE
308  /* input pbuf left over from last session? */
309  pppos_input_free_current_packet(pppos);
310#endif /* PPP_INPROC_IRQ_SAFE */
311
312  /* reset PPPoS control block to its initial state */
313  memset(&pppos->last_xmit, 0, sizeof(pppos_pcb) - offsetof(pppos_pcb, last_xmit));
314
315  /*
316   * Default the in and out accm so that escape and flag characters
317   * are always escaped.
318   */
319  pppos->in_accm[15] = 0x60; /* no need to protect since RX is not running */
320  pppos->out_accm[15] = 0x60;
321  PPPOS_PROTECT(lev);
322  pppos->open = 1;
323  PPPOS_UNPROTECT(lev);
324
325  /*
326   * Start the connection and handle incoming events (packet or timeout).
327   */
328  PPPDEBUG(LOG_INFO, ("pppos_connect: unit %d: connecting\n", ppp->netif->num));
329  ppp_start(ppp); /* notify upper layers */
330}
331
332#if PPP_SERVER
333static void
334pppos_listen(ppp_pcb *ppp, void *ctx)
335{
336  pppos_pcb *pppos = (pppos_pcb *)ctx;
337  PPPOS_DECL_PROTECT(lev);
338
339#if PPP_INPROC_IRQ_SAFE
340  /* input pbuf left over from last session? */
341  pppos_input_free_current_packet(pppos);
342#endif /* PPP_INPROC_IRQ_SAFE */
343
344  /* reset PPPoS control block to its initial state */
345  memset(&pppos->last_xmit, 0, sizeof(pppos_pcb) - offsetof(pppos_pcb, last_xmit));
346
347  /*
348   * Default the in and out accm so that escape and flag characters
349   * are always escaped.
350   */
351  pppos->in_accm[15] = 0x60; /* no need to protect since RX is not running */
352  pppos->out_accm[15] = 0x60;
353  PPPOS_PROTECT(lev);
354  pppos->open = 1;
355  PPPOS_UNPROTECT(lev);
356
357  /*
358   * Wait for something to happen.
359   */
360  PPPDEBUG(LOG_INFO, ("pppos_listen: unit %d: listening\n", ppp->netif->num));
361  ppp_start(ppp); /* notify upper layers */
362}
363#endif /* PPP_SERVER */
364
365static void
366pppos_disconnect(ppp_pcb *ppp, void *ctx)
367{
368  pppos_pcb *pppos = (pppos_pcb *)ctx;
369  PPPOS_DECL_PROTECT(lev);
370
371  PPPOS_PROTECT(lev);
372  pppos->open = 0;
373  PPPOS_UNPROTECT(lev);
374
375  /* If PPP_INPROC_IRQ_SAFE is used we cannot call
376   * pppos_input_free_current_packet() here because
377   * rx IRQ might still call pppos_input().
378   */
379#if !PPP_INPROC_IRQ_SAFE
380  /* input pbuf left ? */
381  pppos_input_free_current_packet(pppos);
382#endif /* !PPP_INPROC_IRQ_SAFE */
383
384  ppp_link_end(ppp); /* notify upper layers */
385}
386
387static err_t
388pppos_destroy(ppp_pcb *ppp, void *ctx)
389{
390  pppos_pcb *pppos = (pppos_pcb *)ctx;
391  LWIP_UNUSED_ARG(ppp);
392
393#if PPP_INPROC_IRQ_SAFE
394  /* input pbuf left ? */
395  pppos_input_free_current_packet(pppos);
396#endif /* PPP_INPROC_IRQ_SAFE */
397
398  LWIP_MEMPOOL_FREE(PPPOS_PCB, pppos);
399  return ERR_OK;
400}
401
402#if !NO_SYS && !PPP_INPROC_IRQ_SAFE
403/** Pass received raw characters to PPPoS to be decoded through lwIP TCPIP thread.
404 *
405 * @param ppp PPP descriptor index, returned by pppos_create()
406 * @param s received data
407 * @param l length of received data
408 */
409err_t
410pppos_input_tcpip(ppp_pcb *ppp, u8_t *s, int l)
411{
412  struct pbuf *p;
413  err_t err;
414
415  p = pbuf_alloc(PBUF_RAW, l, PBUF_POOL);
416  if (!p) {
417    return ERR_MEM;
418  }
419  pbuf_take(p, s, l);
420
421  err = tcpip_inpkt(p, ppp_netif(ppp), pppos_input_sys);
422  if (err != ERR_OK) {
423     pbuf_free(p);
424  }
425  return err;
426}
427
428/* called from TCPIP thread */
429err_t pppos_input_sys(struct pbuf *p, struct netif *inp) {
430  ppp_pcb *ppp = (ppp_pcb*)inp->state;
431  struct pbuf *n;
432
433  for (n = p; n; n = n->next) {
434    pppos_input(ppp, (u8_t*)n->payload, n->len);
435  }
436  pbuf_free(p);
437  return ERR_OK;
438}
439#endif /* !NO_SYS && !PPP_INPROC_IRQ_SAFE */
440
441/** PPPoS input helper struct, must be packed since it is stored
442 * to pbuf->payload, which might be unaligned. */
443#if PPP_INPROC_IRQ_SAFE
444#ifdef PACK_STRUCT_USE_INCLUDES
445#  include "arch/bpstruct.h"
446#endif
447PACK_STRUCT_BEGIN
448struct pppos_input_header {
449  PACK_STRUCT_FIELD(ppp_pcb *ppp);
450} PACK_STRUCT_STRUCT;
451PACK_STRUCT_END
452#ifdef PACK_STRUCT_USE_INCLUDES
453#  include "arch/epstruct.h"
454#endif
455#endif /* PPP_INPROC_IRQ_SAFE */
456
457/** Pass received raw characters to PPPoS to be decoded.
458 *
459 * @param ppp PPP descriptor index, returned by pppos_create()
460 * @param s received data
461 * @param l length of received data
462 */
463void
464pppos_input(ppp_pcb *ppp, u8_t *s, int l)
465{
466  pppos_pcb *pppos = (pppos_pcb *)ppp->link_ctx_cb;
467  struct pbuf *next_pbuf;
468  u8_t cur_char;
469  u8_t escaped;
470  PPPOS_DECL_PROTECT(lev);
471
472  PPPDEBUG(LOG_DEBUG, ("pppos_input[%d]: got %d bytes\n", ppp->netif->num, l));
473  while (l-- > 0) {
474    cur_char = *s++;
475
476    PPPOS_PROTECT(lev);
477    /* ppp_input can disconnect the interface, we need to abort to prevent a memory
478     * leak if there are remaining bytes because pppos_connect and pppos_listen
479     * functions expect input buffer to be free. Furthermore there are no real
480     * reason to continue reading bytes if we are disconnected.
481     */
482    if (!pppos->open) {
483      PPPOS_UNPROTECT(lev);
484      return;
485    }
486    escaped = ESCAPE_P(pppos->in_accm, cur_char);
487    PPPOS_UNPROTECT(lev);
488    /* Handle special characters. */
489    if (escaped) {
490      /* Check for escape sequences. */
491      /* XXX Note that this does not handle an escaped 0x5d character which
492       * would appear as an escape character.  Since this is an ASCII ']'
493       * and there is no reason that I know of to escape it, I won't complicate
494       * the code to handle this case. GLL */
495      if (cur_char == PPP_ESCAPE) {
496        pppos->in_escaped = 1;
497      /* Check for the flag character. */
498      } else if (cur_char == PPP_FLAG) {
499        /* If this is just an extra flag character, ignore it. */
500        if (pppos->in_state <= PDADDRESS) {
501          /* ignore it */;
502        /* If we haven't received the packet header, drop what has come in. */
503        } else if (pppos->in_state < PDDATA) {
504          PPPDEBUG(LOG_WARNING,
505                   ("pppos_input[%d]: Dropping incomplete packet %d\n",
506                    ppp->netif->num, pppos->in_state));
507          LINK_STATS_INC(link.lenerr);
508          pppos_input_drop(pppos);
509        /* If the fcs is invalid, drop the packet. */
510        } else if (pppos->in_fcs != PPP_GOODFCS) {
511          PPPDEBUG(LOG_INFO,
512                   ("pppos_input[%d]: Dropping bad fcs 0x%"X16_F" proto=0x%"X16_F"\n",
513                    ppp->netif->num, pppos->in_fcs, pppos->in_protocol));
514          /* Note: If you get lots of these, check for UART frame errors or try different baud rate */
515          LINK_STATS_INC(link.chkerr);
516          pppos_input_drop(pppos);
517        /* Otherwise it's a good packet so pass it on. */
518        } else {
519          struct pbuf *inp;
520          /* Trim off the checksum. */
521          if(pppos->in_tail->len > 2) {
522            pppos->in_tail->len -= 2;
523
524            pppos->in_tail->tot_len = pppos->in_tail->len;
525            if (pppos->in_tail != pppos->in_head) {
526              pbuf_cat(pppos->in_head, pppos->in_tail);
527            }
528          } else {
529            pppos->in_tail->tot_len = pppos->in_tail->len;
530            if (pppos->in_tail != pppos->in_head) {
531              pbuf_cat(pppos->in_head, pppos->in_tail);
532            }
533
534            pbuf_realloc(pppos->in_head, pppos->in_head->tot_len - 2);
535          }
536
537          /* Dispatch the packet thereby consuming it. */
538          inp = pppos->in_head;
539          /* Packet consumed, release our references. */
540          pppos->in_head = NULL;
541          pppos->in_tail = NULL;
542#if IP_FORWARD || LWIP_IPV6_FORWARD
543          /* hide the room for Ethernet forwarding header */
544          pbuf_header(inp, -(s16_t)(PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN));
545#endif /* IP_FORWARD || LWIP_IPV6_FORWARD */
546#if PPP_INPROC_IRQ_SAFE
547          if(tcpip_callback_with_block(pppos_input_callback, inp, 0) != ERR_OK) {
548            PPPDEBUG(LOG_ERR, ("pppos_input[%d]: tcpip_callback() failed, dropping packet\n", ppp->netif->num));
549            pbuf_free(inp);
550            LINK_STATS_INC(link.drop);
551            MIB2_STATS_NETIF_INC(ppp->netif, ifindiscards);
552          }
553#else /* PPP_INPROC_IRQ_SAFE */
554          ppp_input(ppp, inp);
555#endif /* PPP_INPROC_IRQ_SAFE */
556        }
557
558        /* Prepare for a new packet. */
559        pppos->in_fcs = PPP_INITFCS;
560        pppos->in_state = PDADDRESS;
561        pppos->in_escaped = 0;
562      /* Other characters are usually control characters that may have
563       * been inserted by the physical layer so here we just drop them. */
564      } else {
565        PPPDEBUG(LOG_WARNING,
566                 ("pppos_input[%d]: Dropping ACCM char <%d>\n", ppp->netif->num, cur_char));
567      }
568    /* Process other characters. */
569    } else {
570      /* Unencode escaped characters. */
571      if (pppos->in_escaped) {
572        pppos->in_escaped = 0;
573        cur_char ^= PPP_TRANS;
574      }
575
576      /* Process character relative to current state. */
577      switch(pppos->in_state) {
578        case PDIDLE:                    /* Idle state - waiting. */
579          /* Drop the character if it's not 0xff
580           * we would have processed a flag character above. */
581          if (cur_char != PPP_ALLSTATIONS) {
582            break;
583          }
584          /* no break */
585          /* Fall through */
586
587        case PDSTART:                   /* Process start flag. */
588          /* Prepare for a new packet. */
589          pppos->in_fcs = PPP_INITFCS;
590          /* no break */
591          /* Fall through */
592
593        case PDADDRESS:                 /* Process address field. */
594          if (cur_char == PPP_ALLSTATIONS) {
595            pppos->in_state = PDCONTROL;
596            break;
597          }
598          /* no break */
599
600          /* Else assume compressed address and control fields so
601           * fall through to get the protocol... */
602        case PDCONTROL:                 /* Process control field. */
603          /* If we don't get a valid control code, restart. */
604          if (cur_char == PPP_UI) {
605            pppos->in_state = PDPROTOCOL1;
606            break;
607          }
608          /* no break */
609
610#if 0
611          else {
612            PPPDEBUG(LOG_WARNING,
613                     ("pppos_input[%d]: Invalid control <%d>\n", ppp->netif->num, cur_char));
614            pppos->in_state = PDSTART;
615          }
616#endif
617        case PDPROTOCOL1:               /* Process protocol field 1. */
618          /* If the lower bit is set, this is the end of the protocol
619           * field. */
620          if (cur_char & 1) {
621            pppos->in_protocol = cur_char;
622            pppos->in_state = PDDATA;
623          } else {
624            pppos->in_protocol = (u16_t)cur_char << 8;
625            pppos->in_state = PDPROTOCOL2;
626          }
627          break;
628        case PDPROTOCOL2:               /* Process protocol field 2. */
629          pppos->in_protocol |= cur_char;
630          pppos->in_state = PDDATA;
631          break;
632        case PDDATA:                    /* Process data byte. */
633          /* Make space to receive processed data. */
634          if (pppos->in_tail == NULL || pppos->in_tail->len == PBUF_POOL_BUFSIZE) {
635            u16_t pbuf_alloc_len;
636            if (pppos->in_tail != NULL) {
637              pppos->in_tail->tot_len = pppos->in_tail->len;
638              if (pppos->in_tail != pppos->in_head) {
639                pbuf_cat(pppos->in_head, pppos->in_tail);
640                /* give up the in_tail reference now */
641                pppos->in_tail = NULL;
642              }
643            }
644            /* If we haven't started a packet, we need a packet header. */
645            pbuf_alloc_len = 0;
646#if IP_FORWARD || LWIP_IPV6_FORWARD
647            /* If IP forwarding is enabled we are reserving PBUF_LINK_ENCAPSULATION_HLEN
648             * + PBUF_LINK_HLEN bytes so the packet is being allocated with enough header
649             * space to be forwarded (to Ethernet for example).
650             */
651            if (pppos->in_head == NULL) {
652              pbuf_alloc_len = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN;
653            }
654#endif /* IP_FORWARD || LWIP_IPV6_FORWARD */
655            next_pbuf = pbuf_alloc(PBUF_RAW, pbuf_alloc_len, PBUF_POOL);
656            if (next_pbuf == NULL) {
657              /* No free buffers.  Drop the input packet and let the
658               * higher layers deal with it.  Continue processing
659               * the received pbuf chain in case a new packet starts. */
660              PPPDEBUG(LOG_ERR, ("pppos_input[%d]: NO FREE PBUFS!\n", ppp->netif->num));
661              LINK_STATS_INC(link.memerr);
662              pppos_input_drop(pppos);
663              pppos->in_state = PDSTART;  /* Wait for flag sequence. */
664              break;
665            }
666            if (pppos->in_head == NULL) {
667              u8_t *payload = ((u8_t*)next_pbuf->payload) + pbuf_alloc_len;
668#if PPP_INPROC_IRQ_SAFE
669              ((struct pppos_input_header*)payload)->ppp = ppp;
670              payload += sizeof(struct pppos_input_header);
671              next_pbuf->len += sizeof(struct pppos_input_header);
672#endif /* PPP_INPROC_IRQ_SAFE */
673              next_pbuf->len += sizeof(pppos->in_protocol);
674              *(payload++) = pppos->in_protocol >> 8;
675              *(payload) = pppos->in_protocol & 0xFF;
676              pppos->in_head = next_pbuf;
677            }
678            pppos->in_tail = next_pbuf;
679          }
680          /* Load character into buffer. */
681          ((u8_t*)pppos->in_tail->payload)[pppos->in_tail->len++] = cur_char;
682          break;
683        default:
684          break;
685      }
686
687      /* update the frame check sequence number. */
688      pppos->in_fcs = PPP_FCS(pppos->in_fcs, cur_char);
689    }
690  } /* while (l-- > 0), all bytes processed */
691}
692
693#if PPP_INPROC_IRQ_SAFE
694/* PPPoS input callback using one input pointer
695 */
696static void pppos_input_callback(void *arg) {
697  struct pbuf *pb = (struct pbuf*)arg;
698  ppp_pcb *ppp;
699
700  ppp = ((struct pppos_input_header*)pb->payload)->ppp;
701  if(pbuf_header(pb, -(s16_t)sizeof(struct pppos_input_header))) {
702    LWIP_ASSERT("pbuf_header failed\n", 0);
703    goto drop;
704  }
705
706  /* Dispatch the packet thereby consuming it. */
707  ppp_input(ppp, pb);
708  return;
709
710drop:
711  LINK_STATS_INC(link.drop);
712  MIB2_STATS_NETIF_INC(ppp->netif, ifindiscards);
713  pbuf_free(pb);
714}
715#endif /* PPP_INPROC_IRQ_SAFE */
716
717static void
718pppos_send_config(ppp_pcb *ppp, void *ctx, u32_t accm, int pcomp, int accomp)
719{
720  int i;
721  pppos_pcb *pppos = (pppos_pcb *)ctx;
722  LWIP_UNUSED_ARG(ppp);
723
724  pppos->pcomp = pcomp;
725  pppos->accomp = accomp;
726
727  /* Load the ACCM bits for the 32 control codes. */
728  for (i = 0; i < 32/8; i++) {
729    pppos->out_accm[i] = (u8_t)((accm >> (8 * i)) & 0xFF);
730  }
731
732  PPPDEBUG(LOG_INFO, ("pppos_send_config[%d]: out_accm=%X %X %X %X\n",
733            pppos->ppp->netif->num,
734            pppos->out_accm[0], pppos->out_accm[1], pppos->out_accm[2], pppos->out_accm[3]));
735}
736
737static void
738pppos_recv_config(ppp_pcb *ppp, void *ctx, u32_t accm, int pcomp, int accomp)
739{
740  int i;
741  pppos_pcb *pppos = (pppos_pcb *)ctx;
742  PPPOS_DECL_PROTECT(lev);
743  LWIP_UNUSED_ARG(ppp);
744  LWIP_UNUSED_ARG(pcomp);
745  LWIP_UNUSED_ARG(accomp);
746
747  /* Load the ACCM bits for the 32 control codes. */
748  PPPOS_PROTECT(lev);
749  for (i = 0; i < 32 / 8; i++) {
750    pppos->in_accm[i] = (u8_t)(accm >> (i * 8));
751  }
752  PPPOS_UNPROTECT(lev);
753
754  PPPDEBUG(LOG_INFO, ("pppos_recv_config[%d]: in_accm=%X %X %X %X\n",
755            pppos->ppp->netif->num,
756            pppos->in_accm[0], pppos->in_accm[1], pppos->in_accm[2], pppos->in_accm[3]));
757}
758
759/*
760 * Drop the input packet.
761 */
762static void
763pppos_input_free_current_packet(pppos_pcb *pppos)
764{
765  if (pppos->in_head != NULL) {
766    if (pppos->in_tail && (pppos->in_tail != pppos->in_head)) {
767      pbuf_free(pppos->in_tail);
768    }
769    pbuf_free(pppos->in_head);
770    pppos->in_head = NULL;
771  }
772  pppos->in_tail = NULL;
773}
774
775/*
776 * Drop the input packet and increase error counters.
777 */
778static void
779pppos_input_drop(pppos_pcb *pppos)
780{
781  if (pppos->in_head != NULL) {
782#if 0
783    PPPDEBUG(LOG_INFO, ("pppos_input_drop: %d:%.*H\n", pppos->in_head->len, min(60, pppos->in_head->len * 2), pppos->in_head->payload));
784#endif
785    PPPDEBUG(LOG_INFO, ("pppos_input_drop: pbuf len=%d, addr %p\n", pppos->in_head->len, (void*)pppos->in_head));
786  }
787  pppos_input_free_current_packet(pppos);
788#if VJ_SUPPORT
789  vj_uncompress_err(&pppos->ppp->vj_comp);
790#endif /* VJ_SUPPORT */
791
792  LINK_STATS_INC(link.drop);
793  MIB2_STATS_NETIF_INC(pppos->ppp->netif, ifindiscards);
794}
795
796/*
797 * pppos_output_append - append given character to end of given pbuf.
798 * If out_accm is not 0 and the character needs to be escaped, do so.
799 * If pbuf is full, send the pbuf and reuse it.
800 * Return the current pbuf.
801 */
802static err_t
803pppos_output_append(pppos_pcb *pppos, err_t err, struct pbuf *nb, u8_t c, u8_t accm, u16_t *fcs)
804{
805  if (err != ERR_OK) {
806    return err;
807  }
808
809  /* Make sure there is room for the character and an escape code.
810   * Sure we don't quite fill the buffer if the character doesn't
811   * get escaped but is one character worth complicating this? */
812  if ((PBUF_POOL_BUFSIZE - nb->len) < 2) {
813    u32_t l = pppos->output_cb(pppos->ppp, (u8_t*)nb->payload, nb->len, pppos->ppp->ctx_cb);
814    if (l != nb->len) {
815      return ERR_IF;
816    }
817    nb->len = 0;
818  }
819
820  /* Update FCS before checking for special characters. */
821  if (fcs) {
822    *fcs = PPP_FCS(*fcs, c);
823  }
824
825  /* Copy to output buffer escaping special characters. */
826  if (accm && ESCAPE_P(pppos->out_accm, c)) {
827    *((u8_t*)nb->payload + nb->len++) = PPP_ESCAPE;
828    *((u8_t*)nb->payload + nb->len++) = c ^ PPP_TRANS;
829  } else {
830    *((u8_t*)nb->payload + nb->len++) = c;
831  }
832
833  return ERR_OK;
834}
835
836static err_t
837pppos_output_last(pppos_pcb *pppos, err_t err, struct pbuf *nb, u16_t *fcs)
838{
839  ppp_pcb *ppp = pppos->ppp;
840
841  /* Add FCS and trailing flag. */
842  err = pppos_output_append(pppos, err,  nb, ~(*fcs) & 0xFF, 1, NULL);
843  err = pppos_output_append(pppos, err,  nb, (~(*fcs) >> 8) & 0xFF, 1, NULL);
844  err = pppos_output_append(pppos, err,  nb, PPP_FLAG, 0, NULL);
845
846  if (err != ERR_OK) {
847    goto failed;
848  }
849
850  /* Send remaining buffer if not empty */
851  if (nb->len > 0) {
852    u32_t l = pppos->output_cb(ppp, (u8_t*)nb->payload, nb->len, ppp->ctx_cb);
853    if (l != nb->len) {
854      err = ERR_IF;
855      goto failed;
856    }
857  }
858
859  pppos->last_xmit = sys_now();
860  MIB2_STATS_NETIF_ADD(ppp->netif, ifoutoctets, nb->tot_len);
861  MIB2_STATS_NETIF_INC(ppp->netif, ifoutucastpkts);
862  LINK_STATS_INC(link.xmit);
863  pbuf_free(nb);
864  return ERR_OK;
865
866failed:
867  pppos->last_xmit = 0; /* prepend PPP_FLAG to next packet */
868  LINK_STATS_INC(link.err);
869  LINK_STATS_INC(link.drop);
870  MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards);
871  pbuf_free(nb);
872  return err;
873}
874
875#endif /* PPP_SUPPORT && PPPOS_SUPPORT */
876