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 #include <stddef.h>
39 
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 err_t pppos_connect(ppp_pcb *ppp, void *ctx);
61 #if PPP_SERVER
62 static err_t 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
ppp_get_fcs(u8_t byte)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  */
pppos_create(struct netif * pppif,pppos_output_cb_fn output_cb,ppp_link_status_cb_fn link_status_cb,void * ctx_cb)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
pppos_write(ppp_pcb * ppp,void * ctx,struct pbuf * p)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
pppos_netif_output(ppp_pcb * ppp,void * ctx,struct pbuf * pb,u16_t protocol)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 err_t
pppos_connect(ppp_pcb * ppp,void * ctx)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   return ERR_OK;
331 }
332 
333 #if PPP_SERVER
334 static err_t
pppos_listen(ppp_pcb * ppp,void * ctx)335 pppos_listen(ppp_pcb *ppp, void *ctx)
336 {
337   pppos_pcb *pppos = (pppos_pcb *)ctx;
338   PPPOS_DECL_PROTECT(lev);
339 
340 #if PPP_INPROC_IRQ_SAFE
341   /* input pbuf left over from last session? */
342   pppos_input_free_current_packet(pppos);
343 #endif /* PPP_INPROC_IRQ_SAFE */
344 
345   /* reset PPPoS control block to its initial state */
346   memset(&pppos->last_xmit, 0, sizeof(pppos_pcb) - offsetof(pppos_pcb, last_xmit));
347 
348   /*
349    * Default the in and out accm so that escape and flag characters
350    * are always escaped.
351    */
352   pppos->in_accm[15] = 0x60; /* no need to protect since RX is not running */
353   pppos->out_accm[15] = 0x60;
354   PPPOS_PROTECT(lev);
355   pppos->open = 1;
356   PPPOS_UNPROTECT(lev);
357 
358   /*
359    * Wait for something to happen.
360    */
361   PPPDEBUG(LOG_INFO, ("pppos_listen: unit %d: listening\n", ppp->netif->num));
362   ppp_start(ppp); /* notify upper layers */
363   return ERR_OK;
364 }
365 #endif /* PPP_SERVER */
366 
367 static void
pppos_disconnect(ppp_pcb * ppp,void * ctx)368 pppos_disconnect(ppp_pcb *ppp, void *ctx)
369 {
370   pppos_pcb *pppos = (pppos_pcb *)ctx;
371   PPPOS_DECL_PROTECT(lev);
372 
373   PPPOS_PROTECT(lev);
374   pppos->open = 0;
375   PPPOS_UNPROTECT(lev);
376 
377   /* If PPP_INPROC_IRQ_SAFE is used we cannot call
378    * pppos_input_free_current_packet() here because
379    * rx IRQ might still call pppos_input().
380    */
381 #if !PPP_INPROC_IRQ_SAFE
382   /* input pbuf left ? */
383   pppos_input_free_current_packet(pppos);
384 #endif /* !PPP_INPROC_IRQ_SAFE */
385 
386   ppp_link_end(ppp); /* notify upper layers */
387 }
388 
389 static err_t
pppos_destroy(ppp_pcb * ppp,void * ctx)390 pppos_destroy(ppp_pcb *ppp, void *ctx)
391 {
392   pppos_pcb *pppos = (pppos_pcb *)ctx;
393   LWIP_UNUSED_ARG(ppp);
394 
395 #if PPP_INPROC_IRQ_SAFE
396   /* input pbuf left ? */
397   pppos_input_free_current_packet(pppos);
398 #endif /* PPP_INPROC_IRQ_SAFE */
399 
400   LWIP_MEMPOOL_FREE(PPPOS_PCB, pppos);
401   return ERR_OK;
402 }
403 
404 #if !NO_SYS && !PPP_INPROC_IRQ_SAFE
405 /** Pass received raw characters to PPPoS to be decoded through lwIP TCPIP thread.
406  *
407  * @param ppp PPP descriptor index, returned by pppos_create()
408  * @param s received data
409  * @param l length of received data
410  */
411 err_t
pppos_input_tcpip(ppp_pcb * ppp,u8_t * s,int l)412 pppos_input_tcpip(ppp_pcb *ppp, u8_t *s, int l)
413 {
414   struct pbuf *p;
415   err_t err;
416 
417   p = pbuf_alloc(PBUF_RAW, l, PBUF_POOL);
418   if (!p) {
419     return ERR_MEM;
420   }
421   pbuf_take(p, s, l);
422 
423   err = tcpip_inpkt(p, ppp_netif(ppp), pppos_input_sys);
424   if (err != ERR_OK) {
425      pbuf_free(p);
426   }
427   return err;
428 }
429 
430 /* called from TCPIP thread */
pppos_input_sys(struct pbuf * p,struct netif * inp)431 err_t pppos_input_sys(struct pbuf *p, struct netif *inp) {
432   ppp_pcb *ppp = (ppp_pcb*)inp->state;
433   struct pbuf *n;
434 
435   for (n = p; n; n = n->next) {
436     pppos_input(ppp, (u8_t*)n->payload, n->len);
437   }
438   pbuf_free(p);
439   return ERR_OK;
440 }
441 #endif /* !NO_SYS && !PPP_INPROC_IRQ_SAFE */
442 
443 /** PPPoS input helper struct, must be packed since it is stored
444  * to pbuf->payload, which might be unaligned. */
445 #if PPP_INPROC_IRQ_SAFE
446 #ifdef PACK_STRUCT_USE_INCLUDES
447 #  include "arch/bpstruct.h"
448 #endif
449 PACK_STRUCT_BEGIN
450 struct pppos_input_header {
451   PACK_STRUCT_FIELD(ppp_pcb *ppp);
452 } PACK_STRUCT_STRUCT;
453 PACK_STRUCT_END
454 #ifdef PACK_STRUCT_USE_INCLUDES
455 #  include "arch/epstruct.h"
456 #endif
457 #endif /* PPP_INPROC_IRQ_SAFE */
458 
459 /** Pass received raw characters to PPPoS to be decoded.
460  *
461  * @param ppp PPP descriptor index, returned by pppos_create()
462  * @param s received data
463  * @param l length of received data
464  */
465 void
pppos_input(ppp_pcb * ppp,u8_t * s,int l)466 pppos_input(ppp_pcb *ppp, u8_t *s, int l)
467 {
468   pppos_pcb *pppos = (pppos_pcb *)ppp->link_ctx_cb;
469   struct pbuf *next_pbuf;
470   u8_t cur_char;
471   u8_t escaped;
472   PPPOS_DECL_PROTECT(lev);
473 
474   PPPOS_PROTECT(lev);
475   if (!pppos->open) {
476     PPPOS_UNPROTECT(lev);
477     return;
478   }
479   PPPOS_UNPROTECT(lev);
480 
481   PPPDEBUG(LOG_DEBUG, ("pppos_input[%d]: got %d bytes\n", ppp->netif->num, l));
482   while (l-- > 0) {
483     cur_char = *s++;
484 
485     PPPOS_PROTECT(lev);
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  */
pppos_input_callback(void * arg)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
pppos_send_config(ppp_pcb * ppp,void * ctx,u32_t accm,int pcomp,int accomp)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
pppos_recv_config(ppp_pcb * ppp,void * ctx,u32_t accm,int pcomp,int accomp)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
pppos_input_free_current_packet(pppos_pcb * pppos)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
pppos_input_drop(pppos_pcb * pppos)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
pppos_output_append(pppos_pcb * pppos,err_t err,struct pbuf * nb,u8_t c,u8_t accm,u16_t * fcs)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
pppos_output_last(pppos_pcb * pppos,err_t err,struct pbuf * nb,u16_t * fcs)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 */
876