Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / third_party / lwip / repo / lwip / src / netif / ppp / pppos.c
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 */
55 LWIP_MEMPOOL_DECLARE(PPPOS_PCB, MEMP_NUM_PPPOS_INTERFACES, sizeof(pppos_pcb), "PPPOS_PCB")
56
57 /* callbacks called from PPP core */
58 static err_t pppos_write(ppp_pcb *ppp, void *ctx, struct pbuf *p);
59 static err_t pppos_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *pb, u16_t protocol);
60 static void pppos_connect(ppp_pcb *ppp, void *ctx);
61 #if PPP_SERVER
62 static void pppos_listen(ppp_pcb *ppp, void *ctx);
63 #endif /* PPP_SERVER */
64 static void pppos_disconnect(ppp_pcb *ppp, void *ctx);
65 static err_t pppos_destroy(ppp_pcb *ppp, void *ctx);
66 static void pppos_send_config(ppp_pcb *ppp, void *ctx, u32_t accm, int pcomp, int accomp);
67 static 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
71 static void pppos_input_callback(void *arg);
72 #endif /* PPP_INPROC_IRQ_SAFE */
73 static void pppos_input_free_current_packet(pppos_pcb *pppos);
74 static void pppos_input_drop(pppos_pcb *pppos);
75 static err_t pppos_output_append(pppos_pcb *pppos, err_t err, struct pbuf *nb, u8_t c, u8_t accm, u16_t *fcs);
76 static err_t pppos_output_last(pppos_pcb *pppos, err_t err, struct pbuf *nb, u16_t *fcs);
77
78 /* Callbacks structure for PPP core */
79 static 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  */
100 static 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
138 static u16_t
139 ppp_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  */
174 ppp_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 */
198 static err_t
199 pppos_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 */
246 static err_t
247 pppos_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
301 static void
302 pppos_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
333 static void
334 pppos_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
365 static void
366 pppos_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
387 static err_t
388 pppos_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  */
409 err_t
410 pppos_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 */
429 err_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
447 PACK_STRUCT_BEGIN
448 struct pppos_input_header {
449   PACK_STRUCT_FIELD(ppp_pcb *ppp);
450 } PACK_STRUCT_STRUCT;
451 PACK_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  */
463 void
464 pppos_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  */
696 static 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
710 drop:
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
717 static void
718 pppos_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
737 static void
738 pppos_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  */
762 static void
763 pppos_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  */
778 static void
779 pppos_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  */
802 static err_t
803 pppos_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
836 static err_t
837 pppos_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
866 failed:
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 */