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