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  LWIP_ASSERT_CORE_LOCKED();
180
181  pppos = (pppos_pcb *)LWIP_MEMPOOL_ALLOC(PPPOS_PCB);
182  if (pppos == NULL) {
183    return NULL;
184  }
185
186  ppp = ppp_new(pppif, &pppos_callbacks, pppos, link_status_cb, ctx_cb);
187  if (ppp == NULL) {
188    LWIP_MEMPOOL_FREE(PPPOS_PCB, pppos);
189    return NULL;
190  }
191
192  memset(pppos, 0, sizeof(pppos_pcb));
193  pppos->ppp = ppp;
194  pppos->output_cb = output_cb;
195  return ppp;
196}
197
198/* Called by PPP core */
199static err_t
200pppos_write(ppp_pcb *ppp, void *ctx, struct pbuf *p)
201{
202  pppos_pcb *pppos = (pppos_pcb *)ctx;
203  u8_t *s;
204  struct pbuf *nb;
205  u16_t n;
206  u16_t fcs_out;
207  err_t err;
208  LWIP_UNUSED_ARG(ppp);
209
210  /* Grab an output buffer. Using PBUF_POOL here for tx is ok since the pbuf
211     gets freed by 'pppos_output_last' before this function returns and thus
212     cannot starve rx. */
213  nb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
214  if (nb == NULL) {
215    PPPDEBUG(LOG_WARNING, ("pppos_write[%d]: alloc fail\n", ppp->netif->num));
216    LINK_STATS_INC(link.memerr);
217    LINK_STATS_INC(link.drop);
218    MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards);
219    pbuf_free(p);
220    return ERR_MEM;
221  }
222
223  /* Set nb->tot_len to actual payload length */
224  nb->tot_len = p->len;
225
226  /* If the link has been idle, we'll send a fresh flag character to
227   * flush any noise. */
228  err = ERR_OK;
229  if ((sys_now() - pppos->last_xmit) >= PPP_MAXIDLEFLAG) {
230    err = pppos_output_append(pppos, err,  nb, PPP_FLAG, 0, NULL);
231  }
232
233  /* Load output buffer. */
234  fcs_out = PPP_INITFCS;
235  s = (u8_t*)p->payload;
236  n = p->len;
237  while (n-- > 0) {
238    err = pppos_output_append(pppos, err,  nb, *s++, 1, &fcs_out);
239  }
240
241  err = pppos_output_last(pppos, err, nb, &fcs_out);
242  if (err == ERR_OK) {
243    PPPDEBUG(LOG_INFO, ("pppos_write[%d]: len=%d\n", ppp->netif->num, p->len));
244  } else {
245    PPPDEBUG(LOG_WARNING, ("pppos_write[%d]: output failed len=%d\n", ppp->netif->num, p->len));
246  }
247  pbuf_free(p);
248  return err;
249}
250
251/* Called by PPP core */
252static err_t
253pppos_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *pb, u16_t protocol)
254{
255  pppos_pcb *pppos = (pppos_pcb *)ctx;
256  struct pbuf *nb, *p;
257  u16_t fcs_out;
258  err_t err;
259  LWIP_UNUSED_ARG(ppp);
260
261  /* Grab an output buffer. Using PBUF_POOL here for tx is ok since the pbuf
262     gets freed by 'pppos_output_last' before this function returns and thus
263     cannot starve rx. */
264  nb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
265  if (nb == NULL) {
266    PPPDEBUG(LOG_WARNING, ("pppos_netif_output[%d]: alloc fail\n", ppp->netif->num));
267    LINK_STATS_INC(link.memerr);
268    LINK_STATS_INC(link.drop);
269    MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards);
270    return ERR_MEM;
271  }
272
273  /* Set nb->tot_len to actual payload length */
274  nb->tot_len = pb->tot_len;
275
276  /* If the link has been idle, we'll send a fresh flag character to
277   * flush any noise. */
278  err = ERR_OK;
279  if ((sys_now() - pppos->last_xmit) >= PPP_MAXIDLEFLAG) {
280    err = pppos_output_append(pppos, err,  nb, PPP_FLAG, 0, NULL);
281  }
282
283  fcs_out = PPP_INITFCS;
284  if (!pppos->accomp) {
285    err = pppos_output_append(pppos, err,  nb, PPP_ALLSTATIONS, 1, &fcs_out);
286    err = pppos_output_append(pppos, err,  nb, PPP_UI, 1, &fcs_out);
287  }
288  if (!pppos->pcomp || protocol > 0xFF) {
289    err = pppos_output_append(pppos, err,  nb, (protocol >> 8) & 0xFF, 1, &fcs_out);
290  }
291  err = pppos_output_append(pppos, err,  nb, protocol & 0xFF, 1, &fcs_out);
292
293  /* Load packet. */
294  for(p = pb; p; p = p->next) {
295    u16_t n = p->len;
296    u8_t *s = (u8_t*)p->payload;
297
298    while (n-- > 0) {
299      err = pppos_output_append(pppos, err,  nb, *s++, 1, &fcs_out);
300    }
301  }
302
303  err = pppos_output_last(pppos, err, nb, &fcs_out);
304  if (err == ERR_OK) {
305    PPPDEBUG(LOG_INFO, ("pppos_netif_output[%d]: proto=0x%"X16_F", len = %d\n", ppp->netif->num, protocol, pb->tot_len));
306  } else {
307    PPPDEBUG(LOG_WARNING, ("pppos_netif_output[%d]: output failed proto=0x%"X16_F", len = %d\n", ppp->netif->num, protocol, pb->tot_len));
308  }
309  return err;
310}
311
312static void
313pppos_connect(ppp_pcb *ppp, void *ctx)
314{
315  pppos_pcb *pppos = (pppos_pcb *)ctx;
316  PPPOS_DECL_PROTECT(lev);
317
318#if PPP_INPROC_IRQ_SAFE
319  /* input pbuf left over from last session? */
320  pppos_input_free_current_packet(pppos);
321#endif /* PPP_INPROC_IRQ_SAFE */
322
323  /* reset PPPoS control block to its initial state */
324  memset(&pppos->last_xmit, 0, sizeof(pppos_pcb) - offsetof(pppos_pcb, last_xmit));
325
326  /*
327   * Default the in and out accm so that escape and flag characters
328   * are always escaped.
329   */
330  pppos->in_accm[15] = 0x60; /* no need to protect since RX is not running */
331  pppos->out_accm[15] = 0x60;
332  PPPOS_PROTECT(lev);
333  pppos->open = 1;
334  PPPOS_UNPROTECT(lev);
335
336  /*
337   * Start the connection and handle incoming events (packet or timeout).
338   */
339  PPPDEBUG(LOG_INFO, ("pppos_connect: unit %d: connecting\n", ppp->netif->num));
340  ppp_start(ppp); /* notify upper layers */
341}
342
343#if PPP_SERVER
344static void
345pppos_listen(ppp_pcb *ppp, void *ctx)
346{
347  pppos_pcb *pppos = (pppos_pcb *)ctx;
348  PPPOS_DECL_PROTECT(lev);
349
350#if PPP_INPROC_IRQ_SAFE
351  /* input pbuf left over from last session? */
352  pppos_input_free_current_packet(pppos);
353#endif /* PPP_INPROC_IRQ_SAFE */
354
355  /* reset PPPoS control block to its initial state */
356  memset(&pppos->last_xmit, 0, sizeof(pppos_pcb) - offsetof(pppos_pcb, last_xmit));
357
358  /*
359   * Default the in and out accm so that escape and flag characters
360   * are always escaped.
361   */
362  pppos->in_accm[15] = 0x60; /* no need to protect since RX is not running */
363  pppos->out_accm[15] = 0x60;
364  PPPOS_PROTECT(lev);
365  pppos->open = 1;
366  PPPOS_UNPROTECT(lev);
367
368  /*
369   * Wait for something to happen.
370   */
371  PPPDEBUG(LOG_INFO, ("pppos_listen: unit %d: listening\n", ppp->netif->num));
372  ppp_start(ppp); /* notify upper layers */
373}
374#endif /* PPP_SERVER */
375
376static void
377pppos_disconnect(ppp_pcb *ppp, void *ctx)
378{
379  pppos_pcb *pppos = (pppos_pcb *)ctx;
380  PPPOS_DECL_PROTECT(lev);
381
382  PPPOS_PROTECT(lev);
383  pppos->open = 0;
384  PPPOS_UNPROTECT(lev);
385
386  /* If PPP_INPROC_IRQ_SAFE is used we cannot call
387   * pppos_input_free_current_packet() here because
388   * rx IRQ might still call pppos_input().
389   */
390#if !PPP_INPROC_IRQ_SAFE
391  /* input pbuf left ? */
392  pppos_input_free_current_packet(pppos);
393#endif /* !PPP_INPROC_IRQ_SAFE */
394
395  ppp_link_end(ppp); /* notify upper layers */
396}
397
398static err_t
399pppos_destroy(ppp_pcb *ppp, void *ctx)
400{
401  pppos_pcb *pppos = (pppos_pcb *)ctx;
402  LWIP_UNUSED_ARG(ppp);
403
404#if PPP_INPROC_IRQ_SAFE
405  /* input pbuf left ? */
406  pppos_input_free_current_packet(pppos);
407#endif /* PPP_INPROC_IRQ_SAFE */
408
409  LWIP_MEMPOOL_FREE(PPPOS_PCB, pppos);
410  return ERR_OK;
411}
412
413#if !NO_SYS && !PPP_INPROC_IRQ_SAFE
414/** Pass received raw characters to PPPoS to be decoded through lwIP TCPIP thread.
415 *
416 * This is one of the only functions that may be called outside of the TCPIP thread!
417 *
418 * @param ppp PPP descriptor index, returned by pppos_create()
419 * @param s received data
420 * @param l length of received data
421 */
422err_t
423pppos_input_tcpip(ppp_pcb *ppp, u8_t *s, int l)
424{
425  struct pbuf *p;
426  err_t err;
427
428  p = pbuf_alloc(PBUF_RAW, l, PBUF_POOL);
429  if (!p) {
430    return ERR_MEM;
431  }
432  pbuf_take(p, s, l);
433
434  err = tcpip_inpkt(p, ppp_netif(ppp), pppos_input_sys);
435  if (err != ERR_OK) {
436     pbuf_free(p);
437  }
438  return err;
439}
440
441/* called from TCPIP thread */
442err_t pppos_input_sys(struct pbuf *p, struct netif *inp) {
443  ppp_pcb *ppp = (ppp_pcb*)inp->state;
444  struct pbuf *n;
445  LWIP_ASSERT_CORE_LOCKED();
446
447  for (n = p; n; n = n->next) {
448    pppos_input(ppp, (u8_t*)n->payload, n->len);
449  }
450  pbuf_free(p);
451  return ERR_OK;
452}
453#endif /* !NO_SYS && !PPP_INPROC_IRQ_SAFE */
454
455/** PPPoS input helper struct, must be packed since it is stored
456 * to pbuf->payload, which might be unaligned. */
457#if PPP_INPROC_IRQ_SAFE
458#ifdef PACK_STRUCT_USE_INCLUDES
459#  include "arch/bpstruct.h"
460#endif
461PACK_STRUCT_BEGIN
462struct pppos_input_header {
463  PACK_STRUCT_FIELD(ppp_pcb *ppp);
464} PACK_STRUCT_STRUCT;
465PACK_STRUCT_END
466#ifdef PACK_STRUCT_USE_INCLUDES
467#  include "arch/epstruct.h"
468#endif
469#endif /* PPP_INPROC_IRQ_SAFE */
470
471/** Pass received raw characters to PPPoS to be decoded.
472 *
473 * @param ppp PPP descriptor index, returned by pppos_create()
474 * @param s received data
475 * @param l length of received data
476 */
477void
478pppos_input(ppp_pcb *ppp, u8_t *s, int l)
479{
480  pppos_pcb *pppos = (pppos_pcb *)ppp->link_ctx_cb;
481  struct pbuf *next_pbuf;
482  u8_t cur_char;
483  u8_t escaped;
484  PPPOS_DECL_PROTECT(lev);
485#if !PPP_INPROC_IRQ_SAFE
486  LWIP_ASSERT_CORE_LOCKED();
487#endif
488
489  PPPDEBUG(LOG_DEBUG, ("pppos_input[%d]: got %d bytes\n", ppp->netif->num, l));
490  while (l-- > 0) {
491    cur_char = *s++;
492
493    PPPOS_PROTECT(lev);
494    /* ppp_input can disconnect the interface, we need to abort to prevent a memory
495     * leak if there are remaining bytes because pppos_connect and pppos_listen
496     * functions expect input buffer to be free. Furthermore there are no real
497     * reason to continue reading bytes if we are disconnected.
498     */
499    if (!pppos->open) {
500      PPPOS_UNPROTECT(lev);
501      return;
502    }
503    escaped = ESCAPE_P(pppos->in_accm, cur_char);
504    PPPOS_UNPROTECT(lev);
505    /* Handle special characters. */
506    if (escaped) {
507      /* Check for escape sequences. */
508      /* XXX Note that this does not handle an escaped 0x5d character which
509       * would appear as an escape character.  Since this is an ASCII ']'
510       * and there is no reason that I know of to escape it, I won't complicate
511       * the code to handle this case. GLL */
512      if (cur_char == PPP_ESCAPE) {
513        pppos->in_escaped = 1;
514      /* Check for the flag character. */
515      } else if (cur_char == PPP_FLAG) {
516        /* If this is just an extra flag character, ignore it. */
517        if (pppos->in_state <= PDADDRESS) {
518          /* ignore it */;
519        /* If we haven't received the packet header, drop what has come in. */
520        } else if (pppos->in_state < PDDATA) {
521          PPPDEBUG(LOG_WARNING,
522                   ("pppos_input[%d]: Dropping incomplete packet %d\n",
523                    ppp->netif->num, pppos->in_state));
524          LINK_STATS_INC(link.lenerr);
525          pppos_input_drop(pppos);
526        /* If the fcs is invalid, drop the packet. */
527        } else if (pppos->in_fcs != PPP_GOODFCS) {
528          PPPDEBUG(LOG_INFO,
529                   ("pppos_input[%d]: Dropping bad fcs 0x%"X16_F" proto=0x%"X16_F"\n",
530                    ppp->netif->num, pppos->in_fcs, pppos->in_protocol));
531          /* Note: If you get lots of these, check for UART frame errors or try different baud rate */
532          LINK_STATS_INC(link.chkerr);
533          pppos_input_drop(pppos);
534        /* Otherwise it's a good packet so pass it on. */
535        } else {
536          struct pbuf *inp;
537          /* Trim off the checksum. */
538          if(pppos->in_tail->len > 2) {
539            pppos->in_tail->len -= 2;
540
541            pppos->in_tail->tot_len = pppos->in_tail->len;
542            if (pppos->in_tail != pppos->in_head) {
543              pbuf_cat(pppos->in_head, pppos->in_tail);
544            }
545          } else {
546            pppos->in_tail->tot_len = pppos->in_tail->len;
547            if (pppos->in_tail != pppos->in_head) {
548              pbuf_cat(pppos->in_head, pppos->in_tail);
549            }
550
551            pbuf_realloc(pppos->in_head, pppos->in_head->tot_len - 2);
552          }
553
554          /* Dispatch the packet thereby consuming it. */
555          inp = pppos->in_head;
556          /* Packet consumed, release our references. */
557          pppos->in_head = NULL;
558          pppos->in_tail = NULL;
559#if IP_FORWARD || LWIP_IPV6_FORWARD
560          /* hide the room for Ethernet forwarding header */
561          pbuf_remove_header(inp, PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN);
562#endif /* IP_FORWARD || LWIP_IPV6_FORWARD */
563#if PPP_INPROC_IRQ_SAFE
564          if(tcpip_try_callback(pppos_input_callback, inp) != ERR_OK) {
565            PPPDEBUG(LOG_ERR, ("pppos_input[%d]: tcpip_callback() failed, dropping packet\n", ppp->netif->num));
566            pbuf_free(inp);
567            LINK_STATS_INC(link.drop);
568            MIB2_STATS_NETIF_INC(ppp->netif, ifindiscards);
569          }
570#else /* PPP_INPROC_IRQ_SAFE */
571          ppp_input(ppp, inp);
572#endif /* PPP_INPROC_IRQ_SAFE */
573        }
574
575        /* Prepare for a new packet. */
576        pppos->in_fcs = PPP_INITFCS;
577        pppos->in_state = PDADDRESS;
578        pppos->in_escaped = 0;
579      /* Other characters are usually control characters that may have
580       * been inserted by the physical layer so here we just drop them. */
581      } else {
582        PPPDEBUG(LOG_WARNING,
583                 ("pppos_input[%d]: Dropping ACCM char <%d>\n", ppp->netif->num, cur_char));
584      }
585    /* Process other characters. */
586    } else {
587      /* Unencode escaped characters. */
588      if (pppos->in_escaped) {
589        pppos->in_escaped = 0;
590        cur_char ^= PPP_TRANS;
591      }
592
593      /* Process character relative to current state. */
594      switch(pppos->in_state) {
595        case PDIDLE:                    /* Idle state - waiting. */
596          /* Drop the character if it's not 0xff
597           * we would have processed a flag character above. */
598          if (cur_char != PPP_ALLSTATIONS) {
599            break;
600          }
601          /* no break */
602          /* Fall through */
603
604        case PDSTART:                   /* Process start flag. */
605          /* Prepare for a new packet. */
606          pppos->in_fcs = PPP_INITFCS;
607          /* no break */
608          /* Fall through */
609
610        case PDADDRESS:                 /* Process address field. */
611          if (cur_char == PPP_ALLSTATIONS) {
612            pppos->in_state = PDCONTROL;
613            break;
614          }
615          /* no break */
616
617          /* Else assume compressed address and control fields so
618           * fall through to get the protocol... */
619          /* Fall through */
620        case PDCONTROL:                 /* Process control field. */
621          /* If we don't get a valid control code, restart. */
622          if (cur_char == PPP_UI) {
623            pppos->in_state = PDPROTOCOL1;
624            break;
625          }
626          /* no break */
627
628#if 0
629          else {
630            PPPDEBUG(LOG_WARNING,
631                     ("pppos_input[%d]: Invalid control <%d>\n", ppp->netif->num, cur_char));
632            pppos->in_state = PDSTART;
633          }
634#endif
635          /* Fall through */
636
637      case PDPROTOCOL1:               /* Process protocol field 1. */
638          /* If the lower bit is set, this is the end of the protocol
639           * field. */
640          if (cur_char & 1) {
641            pppos->in_protocol = cur_char;
642            pppos->in_state = PDDATA;
643          } else {
644            pppos->in_protocol = (u16_t)cur_char << 8;
645            pppos->in_state = PDPROTOCOL2;
646          }
647          break;
648        case PDPROTOCOL2:               /* Process protocol field 2. */
649          pppos->in_protocol |= cur_char;
650          pppos->in_state = PDDATA;
651          break;
652        case PDDATA:                    /* Process data byte. */
653          /* Make space to receive processed data. */
654          if (pppos->in_tail == NULL || pppos->in_tail->len == PBUF_POOL_BUFSIZE) {
655            u16_t pbuf_alloc_len;
656            if (pppos->in_tail != NULL) {
657              pppos->in_tail->tot_len = pppos->in_tail->len;
658              if (pppos->in_tail != pppos->in_head) {
659                pbuf_cat(pppos->in_head, pppos->in_tail);
660                /* give up the in_tail reference now */
661                pppos->in_tail = NULL;
662              }
663            }
664            /* If we haven't started a packet, we need a packet header. */
665            pbuf_alloc_len = 0;
666#if IP_FORWARD || LWIP_IPV6_FORWARD
667            /* If IP forwarding is enabled we are reserving PBUF_LINK_ENCAPSULATION_HLEN
668             * + PBUF_LINK_HLEN bytes so the packet is being allocated with enough header
669             * space to be forwarded (to Ethernet for example).
670             */
671            if (pppos->in_head == NULL) {
672              pbuf_alloc_len = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN;
673            }
674#endif /* IP_FORWARD || LWIP_IPV6_FORWARD */
675            next_pbuf = pbuf_alloc(PBUF_RAW, pbuf_alloc_len, PBUF_POOL);
676            if (next_pbuf == NULL) {
677              /* No free buffers.  Drop the input packet and let the
678               * higher layers deal with it.  Continue processing
679               * the received pbuf chain in case a new packet starts. */
680              PPPDEBUG(LOG_ERR, ("pppos_input[%d]: NO FREE PBUFS!\n", ppp->netif->num));
681              LINK_STATS_INC(link.memerr);
682              pppos_input_drop(pppos);
683              pppos->in_state = PDSTART;  /* Wait for flag sequence. */
684              break;
685            }
686            if (pppos->in_head == NULL) {
687              u8_t *payload = ((u8_t*)next_pbuf->payload) + pbuf_alloc_len;
688#if PPP_INPROC_IRQ_SAFE
689              ((struct pppos_input_header*)payload)->ppp = ppp;
690              payload += sizeof(struct pppos_input_header);
691              next_pbuf->len += sizeof(struct pppos_input_header);
692#endif /* PPP_INPROC_IRQ_SAFE */
693              next_pbuf->len += sizeof(pppos->in_protocol);
694              *(payload++) = pppos->in_protocol >> 8;
695              *(payload) = pppos->in_protocol & 0xFF;
696              pppos->in_head = next_pbuf;
697            }
698            pppos->in_tail = next_pbuf;
699          }
700          /* Load character into buffer. */
701          ((u8_t*)pppos->in_tail->payload)[pppos->in_tail->len++] = cur_char;
702          break;
703        default:
704          break;
705      }
706
707      /* update the frame check sequence number. */
708      pppos->in_fcs = PPP_FCS(pppos->in_fcs, cur_char);
709    }
710  } /* while (l-- > 0), all bytes processed */
711}
712
713#if PPP_INPROC_IRQ_SAFE
714/* PPPoS input callback using one input pointer
715 */
716static void pppos_input_callback(void *arg) {
717  struct pbuf *pb = (struct pbuf*)arg;
718  ppp_pcb *ppp;
719
720  ppp = ((struct pppos_input_header*)pb->payload)->ppp;
721  if(pbuf_remove_header(pb, sizeof(struct pppos_input_header))) {
722    LWIP_ASSERT("pbuf_remove_header failed\n", 0);
723    goto drop;
724  }
725
726  /* Dispatch the packet thereby consuming it. */
727  ppp_input(ppp, pb);
728  return;
729
730drop:
731  LINK_STATS_INC(link.drop);
732  MIB2_STATS_NETIF_INC(ppp->netif, ifindiscards);
733  pbuf_free(pb);
734}
735#endif /* PPP_INPROC_IRQ_SAFE */
736
737static void
738pppos_send_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  LWIP_UNUSED_ARG(ppp);
743
744  pppos->pcomp = pcomp;
745  pppos->accomp = accomp;
746
747  /* Load the ACCM bits for the 32 control codes. */
748  for (i = 0; i < 32/8; i++) {
749    pppos->out_accm[i] = (u8_t)((accm >> (8 * i)) & 0xFF);
750  }
751
752  PPPDEBUG(LOG_INFO, ("pppos_send_config[%d]: out_accm=%X %X %X %X\n",
753            pppos->ppp->netif->num,
754            pppos->out_accm[0], pppos->out_accm[1], pppos->out_accm[2], pppos->out_accm[3]));
755}
756
757static void
758pppos_recv_config(ppp_pcb *ppp, void *ctx, u32_t accm, int pcomp, int accomp)
759{
760  int i;
761  pppos_pcb *pppos = (pppos_pcb *)ctx;
762  PPPOS_DECL_PROTECT(lev);
763  LWIP_UNUSED_ARG(ppp);
764  LWIP_UNUSED_ARG(pcomp);
765  LWIP_UNUSED_ARG(accomp);
766
767  /* Load the ACCM bits for the 32 control codes. */
768  PPPOS_PROTECT(lev);
769  for (i = 0; i < 32 / 8; i++) {
770    pppos->in_accm[i] = (u8_t)(accm >> (i * 8));
771  }
772  PPPOS_UNPROTECT(lev);
773
774  PPPDEBUG(LOG_INFO, ("pppos_recv_config[%d]: in_accm=%X %X %X %X\n",
775            pppos->ppp->netif->num,
776            pppos->in_accm[0], pppos->in_accm[1], pppos->in_accm[2], pppos->in_accm[3]));
777}
778
779/*
780 * Drop the input packet.
781 */
782static void
783pppos_input_free_current_packet(pppos_pcb *pppos)
784{
785  if (pppos->in_head != NULL) {
786    if (pppos->in_tail && (pppos->in_tail != pppos->in_head)) {
787      pbuf_free(pppos->in_tail);
788    }
789    pbuf_free(pppos->in_head);
790    pppos->in_head = NULL;
791  }
792  pppos->in_tail = NULL;
793}
794
795/*
796 * Drop the input packet and increase error counters.
797 */
798static void
799pppos_input_drop(pppos_pcb *pppos)
800{
801  if (pppos->in_head != NULL) {
802#if 0
803    PPPDEBUG(LOG_INFO, ("pppos_input_drop: %d:%.*H\n", pppos->in_head->len, min(60, pppos->in_head->len * 2), pppos->in_head->payload));
804#endif
805    PPPDEBUG(LOG_INFO, ("pppos_input_drop: pbuf len=%d, addr %p\n", pppos->in_head->len, (void*)pppos->in_head));
806  }
807  pppos_input_free_current_packet(pppos);
808#if VJ_SUPPORT
809  vj_uncompress_err(&pppos->ppp->vj_comp);
810#endif /* VJ_SUPPORT */
811
812  LINK_STATS_INC(link.drop);
813  MIB2_STATS_NETIF_INC(pppos->ppp->netif, ifindiscards);
814}
815
816/*
817 * pppos_output_append - append given character to end of given pbuf.
818 * If out_accm is not 0 and the character needs to be escaped, do so.
819 * If pbuf is full, send the pbuf and reuse it.
820 * Return the current pbuf.
821 */
822static err_t
823pppos_output_append(pppos_pcb *pppos, err_t err, struct pbuf *nb, u8_t c, u8_t accm, u16_t *fcs)
824{
825  if (err != ERR_OK) {
826    return err;
827  }
828
829  /* Make sure there is room for the character and an escape code.
830   * Sure we don't quite fill the buffer if the character doesn't
831   * get escaped but is one character worth complicating this? */
832  if ((PBUF_POOL_BUFSIZE - nb->len) < 2) {
833    u32_t l = pppos->output_cb(pppos->ppp, (u8_t*)nb->payload, nb->len, pppos->ppp->ctx_cb);
834    if (l != nb->len) {
835      return ERR_IF;
836    }
837    nb->len = 0;
838  }
839
840  /* Update FCS before checking for special characters. */
841  if (fcs) {
842    *fcs = PPP_FCS(*fcs, c);
843  }
844
845  /* Copy to output buffer escaping special characters. */
846  if (accm && ESCAPE_P(pppos->out_accm, c)) {
847    *((u8_t*)nb->payload + nb->len++) = PPP_ESCAPE;
848    *((u8_t*)nb->payload + nb->len++) = c ^ PPP_TRANS;
849  } else {
850    *((u8_t*)nb->payload + nb->len++) = c;
851  }
852
853  return ERR_OK;
854}
855
856static err_t
857pppos_output_last(pppos_pcb *pppos, err_t err, struct pbuf *nb, u16_t *fcs)
858{
859  ppp_pcb *ppp = pppos->ppp;
860
861  /* Add FCS and trailing flag. */
862  err = pppos_output_append(pppos, err,  nb, ~(*fcs) & 0xFF, 1, NULL);
863  err = pppos_output_append(pppos, err,  nb, (~(*fcs) >> 8) & 0xFF, 1, NULL);
864  err = pppos_output_append(pppos, err,  nb, PPP_FLAG, 0, NULL);
865
866  if (err != ERR_OK) {
867    goto failed;
868  }
869
870  /* Send remaining buffer if not empty */
871  if (nb->len > 0) {
872    u32_t l = pppos->output_cb(ppp, (u8_t*)nb->payload, nb->len, ppp->ctx_cb);
873    if (l != nb->len) {
874      err = ERR_IF;
875      goto failed;
876    }
877  }
878
879  pppos->last_xmit = sys_now();
880  MIB2_STATS_NETIF_ADD(ppp->netif, ifoutoctets, nb->tot_len);
881  MIB2_STATS_NETIF_INC(ppp->netif, ifoutucastpkts);
882  LINK_STATS_INC(link.xmit);
883  pbuf_free(nb);
884  return ERR_OK;
885
886failed:
887  pppos->last_xmit = 0; /* prepend PPP_FLAG to next packet */
888  LINK_STATS_INC(link.err);
889  LINK_STATS_INC(link.drop);
890  MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards);
891  pbuf_free(nb);
892  return err;
893}
894
895#endif /* PPP_SUPPORT && PPPOS_SUPPORT */
896