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