STM32F769IDiscovery  1.00
uDANTE Audio Networking with STM32F7 DISCO board
pppos.c
Go to the documentation of this file.
1 
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 "lwip/opt.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/err.h"
40 #include "lwip/pbuf.h"
41 #include "lwip/sys.h"
42 #include "lwip/memp.h"
43 #include "lwip/netif.h"
44 #include "lwip/snmp.h"
45 #include "lwip/priv/tcpip_priv.h"
46 #include "lwip/api.h"
47 #include "lwip/ip4.h" /* for ip4_input() */
48 
49 #include "netif/ppp/ppp_impl.h"
50 #include "netif/ppp/pppos.h"
51 #include "netif/ppp/vj.h"
52 
53 /* callbacks called from PPP core */
54 static err_t pppos_write(ppp_pcb *ppp, void *ctx, struct pbuf *p);
55 static err_t pppos_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *pb, u16_t protocol);
56 static err_t pppos_connect(ppp_pcb *ppp, void *ctx);
57 #if PPP_SERVER
58 static err_t pppos_listen(ppp_pcb *ppp, void *ctx, struct ppp_addrs *addrs);
59 #endif /* PPP_SERVER */
60 static void pppos_disconnect(ppp_pcb *ppp, void *ctx);
61 static err_t pppos_destroy(ppp_pcb *ppp, void *ctx);
62 static void pppos_send_config(ppp_pcb *ppp, void *ctx, u32_t accm, int pcomp, int accomp);
63 static void pppos_recv_config(ppp_pcb *ppp, void *ctx, u32_t accm, int pcomp, int accomp);
64 
65 /* Prototypes for procedures local to this file. */
66 #if PPP_INPROC_IRQ_SAFE
67 static void pppos_input_callback(void *arg);
68 #endif /* PPP_INPROC_IRQ_SAFE */
69 static void pppos_input_free_current_packet(pppos_pcb *pppos);
70 static void pppos_input_drop(pppos_pcb *pppos);
71 static err_t pppos_output_append(pppos_pcb *pppos, err_t err, struct pbuf *nb, u8_t c, u8_t accm, u16_t *fcs);
72 static err_t pppos_output_last(pppos_pcb *pppos, err_t err, struct pbuf *nb, u16_t *fcs);
73 
74 /* Callbacks structure for PPP core */
75 static const struct link_callbacks pppos_callbacks = {
76  pppos_connect,
77 #if PPP_SERVER
78  pppos_listen,
79 #endif /* PPP_SERVER */
80  pppos_disconnect,
81  pppos_destroy,
82  pppos_write,
83  pppos_netif_output,
84  pppos_send_config,
85  pppos_recv_config
86 };
87 
88 /* PPP's Asynchronous-Control-Character-Map. The mask array is used
89  * to select the specific bit for a character. */
90 #define ESCAPE_P(accm, c) ((accm)[(c) >> 3] & 1 << (c & 0x07))
91 
92 #if PPP_FCS_TABLE
93 /*
94  * FCS lookup table as calculated by genfcstab.
95  */
96 static const u16_t fcstab[256] = {
97  0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
98  0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
99  0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
100  0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
101  0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
102  0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
103  0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
104  0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
105  0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
106  0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
107  0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
108  0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
109  0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
110  0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
111  0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
112  0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
113  0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
114  0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
115  0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
116  0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
117  0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
118  0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
119  0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
120  0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
121  0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
122  0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
123  0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
124  0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
125  0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
126  0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
127  0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
128  0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
129 };
130 #define PPP_FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
131 #else /* PPP_FCS_TABLE */
132 /* The HDLC polynomial: X**0 + X**5 + X**12 + X**16 (0x8408) */
133 #define PPP_FCS_POLYNOMIAL 0x8408
134 static u16_t
135 ppp_get_fcs(u8_t byte)
136 {
137  unsigned int octet;
138  int bit;
139  octet = byte;
140  for (bit = 8; bit-- > 0; ) {
141  octet = (octet & 0x01) ? ((octet >> 1) ^ PPP_FCS_POLYNOMIAL) : (octet >> 1);
142  }
143  return octet & 0xffff;
144 }
145 #define PPP_FCS(fcs, c) (((fcs) >> 8) ^ ppp_get_fcs(((fcs) ^ (c)) & 0xff))
146 #endif /* PPP_FCS_TABLE */
147 
148 /*
149  * Values for FCS calculations.
150  */
151 #define PPP_INITFCS 0xffff /* Initial FCS value */
152 #define PPP_GOODFCS 0xf0b8 /* Good final FCS value */
153 
154 #if PPP_INPROC_IRQ_SAFE
155 #define PPPOS_DECL_PROTECT(lev) SYS_ARCH_DECL_PROTECT(lev)
156 #define PPPOS_PROTECT(lev) SYS_ARCH_PROTECT(lev)
157 #define PPPOS_UNPROTECT(lev) SYS_ARCH_UNPROTECT(lev)
158 #else
159 #define PPPOS_DECL_PROTECT(lev)
160 #define PPPOS_PROTECT(lev)
161 #define PPPOS_UNPROTECT(lev)
162 #endif /* PPP_INPROC_IRQ_SAFE */
163 
164 
165 /*
166  * Create a new PPP connection using the given serial I/O device.
167  *
168  * Return 0 on success, an error code on failure.
169  */
170 ppp_pcb *pppos_create(struct netif *pppif, pppos_output_cb_fn output_cb,
171  ppp_link_status_cb_fn link_status_cb, void *ctx_cb)
172 {
173  pppos_pcb *pppos;
174  ppp_pcb *ppp;
175 
176  pppos = (pppos_pcb *)memp_malloc(MEMP_PPPOS_PCB);
177  if (pppos == NULL) {
178  return NULL;
179  }
180 
181  ppp = ppp_new(pppif, &pppos_callbacks, pppos, link_status_cb, ctx_cb);
182  if (ppp == NULL) {
183  memp_free(MEMP_PPPOS_PCB, pppos);
184  return NULL;
185  }
186 
187  memset(pppos, 0, sizeof(pppos_pcb));
188  pppos->ppp = ppp;
189  pppos->output_cb = output_cb;
190  return ppp;
191 }
192 
193 /* Called by PPP core */
194 static err_t
195 pppos_write(ppp_pcb *ppp, void *ctx, struct pbuf *p)
196 {
197  pppos_pcb *pppos = (pppos_pcb *)ctx;
198  u8_t *s;
199  struct pbuf *nb;
200  u16_t n;
201  u16_t fcs_out;
202  err_t err;
203  LWIP_UNUSED_ARG(ppp);
204 
205  /* Grab an output buffer. */
206  nb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
207  if (nb == NULL) {
208  PPPDEBUG(LOG_WARNING, ("pppos_write[%d]: alloc fail\n", ppp->netif->num));
209  LINK_STATS_INC(link.memerr);
210  LINK_STATS_INC(link.drop);
211  MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards);
212  pbuf_free(p);
213  return ERR_MEM;
214  }
215 
216  /* If the link has been idle, we'll send a fresh flag character to
217  * flush any noise. */
218  err = ERR_OK;
219  if ((sys_now() - pppos->last_xmit) >= PPP_MAXIDLEFLAG) {
220  err = pppos_output_append(pppos, err, nb, PPP_FLAG, 0, NULL);
221  }
222 
223  /* Load output buffer. */
224  fcs_out = PPP_INITFCS;
225  s = (u8_t*)p->payload;
226  n = p->len;
227  while (n-- > 0) {
228  err = pppos_output_append(pppos, err, nb, *s++, 1, &fcs_out);
229  }
230 
231  err = pppos_output_last(pppos, err, nb, &fcs_out);
232  if (err == ERR_OK) {
233  PPPDEBUG(LOG_INFO, ("pppos_write[%d]: len=%d\n", ppp->netif->num, p->len));
234  } else {
235  PPPDEBUG(LOG_WARNING, ("pppos_write[%d]: output failed len=%d\n", ppp->netif->num, p->len));
236  }
237  pbuf_free(p);
238  return err;
239 }
240 
241 /* Called by PPP core */
242 static err_t
243 pppos_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *pb, u16_t protocol)
244 {
245  pppos_pcb *pppos = (pppos_pcb *)ctx;
246  struct pbuf *nb, *p;
247  u16_t fcs_out;
248  err_t err;
249  LWIP_UNUSED_ARG(ppp);
250 
251  /* Grab an output buffer. */
252  nb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
253  if (nb == NULL) {
254  PPPDEBUG(LOG_WARNING, ("pppos_netif_output[%d]: alloc fail\n", ppp->netif->num));
255  LINK_STATS_INC(link.memerr);
256  LINK_STATS_INC(link.drop);
257  MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards);
258  return ERR_MEM;
259  }
260 
261  /* If the link has been idle, we'll send a fresh flag character to
262  * flush any noise. */
263  err = ERR_OK;
264  if ((sys_now() - pppos->last_xmit) >= PPP_MAXIDLEFLAG) {
265  err = pppos_output_append(pppos, err, nb, PPP_FLAG, 0, NULL);
266  }
267 
268  fcs_out = PPP_INITFCS;
269  if (!pppos->accomp) {
270  err = pppos_output_append(pppos, err, nb, PPP_ALLSTATIONS, 1, &fcs_out);
271  err = pppos_output_append(pppos, err, nb, PPP_UI, 1, &fcs_out);
272  }
273  if (!pppos->pcomp || protocol > 0xFF) {
274  err = pppos_output_append(pppos, err, nb, (protocol >> 8) & 0xFF, 1, &fcs_out);
275  }
276  err = pppos_output_append(pppos, err, nb, protocol & 0xFF, 1, &fcs_out);
277 
278  /* Load packet. */
279  for(p = pb; p; p = p->next) {
280  u16_t n = p->len;
281  u8_t *s = (u8_t*)p->payload;
282 
283  while (n-- > 0) {
284  err = pppos_output_append(pppos, err, nb, *s++, 1, &fcs_out);
285  }
286  }
287 
288  err = pppos_output_last(pppos, err, nb, &fcs_out);
289  if (err == ERR_OK) {
290  PPPDEBUG(LOG_INFO, ("pppos_netif_output[%d]: proto=0x%"X16_F", len = %d\n", ppp->netif->num, protocol, pb->tot_len));
291  } else {
292  PPPDEBUG(LOG_WARNING, ("pppos_netif_output[%d]: output failed proto=0x%"X16_F", len = %d\n", ppp->netif->num, protocol, pb->tot_len));
293  }
294  return err;
295 }
296 
297 static err_t
298 pppos_connect(ppp_pcb *ppp, void *ctx)
299 {
300  pppos_pcb *pppos = (pppos_pcb *)ctx;
301  PPPOS_DECL_PROTECT(lev);
302 
303 #if PPP_INPROC_IRQ_SAFE
304  /* input pbuf left over from last session? */
305  pppos_input_free_current_packet(pppos);
306 #endif /* PPP_INPROC_IRQ_SAFE */
307 
308  ppp_clear(ppp);
309  /* reset PPPoS control block to its initial state */
310  memset(&pppos->last_xmit, 0, sizeof(pppos_pcb) - ( (char*)&((pppos_pcb*)0)->last_xmit - (char*)0 ) );
311 
312  /*
313  * Default the in and out accm so that escape and flag characters
314  * are always escaped.
315  */
316  pppos->in_accm[15] = 0x60; /* no need to protect since RX is not running */
317  pppos->out_accm[15] = 0x60;
318  PPPOS_PROTECT(lev);
319  pppos->open = 1;
320  PPPOS_UNPROTECT(lev);
321 
322  /*
323  * Start the connection and handle incoming events (packet or timeout).
324  */
325  PPPDEBUG(LOG_INFO, ("pppos_connect: unit %d: connecting\n", ppp->netif->num));
326  ppp_start(ppp); /* notify upper layers */
327  return ERR_OK;
328 }
329 
330 #if PPP_SERVER
331 static err_t
332 pppos_listen(ppp_pcb *ppp, void *ctx, struct ppp_addrs *addrs)
333 {
334  pppos_pcb *pppos = (pppos_pcb *)ctx;
335 #if PPP_IPV4_SUPPORT
336  ipcp_options *ipcp_wo;
337 #endif /* PPP_IPV4_SUPPORT */
338  lcp_options *lcp_wo;
339  PPPOS_DECL_PROTECT(lev);
340 
341 #if PPP_INPROC_IRQ_SAFE
342  /* input pbuf left over from last session? */
343  pppos_input_free_current_packet(pppos);
344 #endif /* PPP_INPROC_IRQ_SAFE */
345 
346  ppp_clear(ppp);
347  /* reset PPPoS control block to its initial state */
348  memset(&pppos->last_xmit, 0, sizeof(pppos_pcb) - ( (char*)&((pppos_pcb*)0)->last_xmit - (char*)0 ) );
349 
350  /* Wait passively */
351  lcp_wo = &ppp->lcp_wantoptions;
352  lcp_wo->silent = 1;
353 
354 #if PPP_AUTH_SUPPORT
355  if (ppp->settings.user && ppp->settings.passwd) {
356  ppp->settings.auth_required = 1;
357  }
358 #endif /* PPP_AUTH_SUPPORT */
359 
360 #if PPP_IPV4_SUPPORT
361  ipcp_wo = &ppp->ipcp_wantoptions;
362  ipcp_wo->ouraddr = ip4_addr_get_u32(&addrs->our_ipaddr);
363  ipcp_wo->hisaddr = ip4_addr_get_u32(&addrs->his_ipaddr);
364 #if LWIP_DNS
365  ipcp_wo->dnsaddr[0] = ip4_addr_get_u32(&addrs->dns1);
366  ipcp_wo->dnsaddr[1] = ip4_addr_get_u32(&addrs->dns2);
367 #endif /* LWIP_DNS */
368 #else /* PPP_IPV4_SUPPORT */
369  LWIP_UNUSED_ARG(addrs);
370 #endif /* PPP_IPV4_SUPPORT */
371 
372  /*
373  * Default the in and out accm so that escape and flag characters
374  * are always escaped.
375  */
376  pppos->in_accm[15] = 0x60; /* no need to protect since RX is not running */
377  pppos->out_accm[15] = 0x60;
378  PPPOS_PROTECT(lev);
379  pppos->open = 1;
380  PPPOS_UNPROTECT(lev);
381 
382  /*
383  * Wait for something to happen.
384  */
385  PPPDEBUG(LOG_INFO, ("pppos_listen: unit %d: listening\n", ppp->netif->num));
386  ppp_start(ppp); /* notify upper layers */
387  return ERR_OK;
388 }
389 #endif /* PPP_SERVER */
390 
391 static void
392 pppos_disconnect(ppp_pcb *ppp, void *ctx)
393 {
394  pppos_pcb *pppos = (pppos_pcb *)ctx;
395  PPPOS_DECL_PROTECT(lev);
396 
397  PPPOS_PROTECT(lev);
398  pppos->open = 0;
399  PPPOS_UNPROTECT(lev);
400 
401  /* If PPP_INPROC_IRQ_SAFE is used we cannot call
402  * pppos_input_free_current_packet() here because
403  * rx IRQ might still call pppos_input().
404  */
405 #if !PPP_INPROC_IRQ_SAFE
406  /* input pbuf left ? */
407  pppos_input_free_current_packet(pppos);
408 #endif /* !PPP_INPROC_IRQ_SAFE */
409 
410  ppp_link_end(ppp); /* notify upper layers */
411 }
412 
413 static err_t
414 pppos_destroy(ppp_pcb *ppp, void *ctx)
415 {
416  pppos_pcb *pppos = (pppos_pcb *)ctx;
417  LWIP_UNUSED_ARG(ppp);
418 
419 #if PPP_INPROC_IRQ_SAFE
420  /* input pbuf left ? */
421  pppos_input_free_current_packet(pppos);
422 #endif /* PPP_INPROC_IRQ_SAFE */
423 
424  memp_free(MEMP_PPPOS_PCB, pppos);
425  return ERR_OK;
426 }
427 
428 #if !NO_SYS && !PPP_INPROC_IRQ_SAFE
429 
435 err_t
436 pppos_input_tcpip(ppp_pcb *ppp, u8_t *s, int l)
437 {
438  struct pbuf *p;
439  err_t err;
440 
441  p = pbuf_alloc(PBUF_RAW, l, PBUF_POOL);
442  if (!p) {
443  return ERR_MEM;
444  }
445  pbuf_take(p, s, l);
446 
447  err = tcpip_pppos_input(p, ppp_netif(ppp));
448  if (err != ERR_OK) {
449  pbuf_free(p);
450  }
451  return err;
452 }
453 
454 /* called from TCPIP thread */
455 err_t pppos_input_sys(struct pbuf *p, struct netif *inp) {
456  ppp_pcb *ppp = (ppp_pcb*)inp->state;
457  struct pbuf *n;
458 
459  for (n = p; n; n = n->next) {
460  pppos_input(ppp, (u8_t*)n->payload, n->len);
461  }
462  pbuf_free(p);
463  return ERR_OK;
464 }
465 #endif /* !NO_SYS && !PPP_INPROC_IRQ_SAFE */
466 
469 #if PPP_INPROC_IRQ_SAFE
470 #ifdef PACK_STRUCT_USE_INCLUDES
471 # include "arch/bpstruct.h"
472 #endif
474 struct pppos_input_header {
475  PACK_STRUCT_FIELD(ppp_pcb *ppp);
478 #ifdef PACK_STRUCT_USE_INCLUDES
479 # include "arch/epstruct.h"
480 #endif
481 #endif /* PPP_INPROC_IRQ_SAFE */
482 
489 void
490 pppos_input(ppp_pcb *ppp, u8_t *s, int l)
491 {
492  pppos_pcb *pppos = (pppos_pcb *)ppp->link_ctx_cb;
493  struct pbuf *next_pbuf;
494  u8_t cur_char;
495  u8_t escaped;
496  PPPOS_DECL_PROTECT(lev);
497 
498  PPPOS_PROTECT(lev);
499  if (!pppos->open) {
500  PPPOS_UNPROTECT(lev);
501  return;
502  }
503  PPPOS_UNPROTECT(lev);
504 
505  PPPDEBUG(LOG_DEBUG, ("pppos_input[%d]: got %d bytes\n", ppp->netif->num, l));
506  while (l-- > 0) {
507  cur_char = *s++;
508 
509  PPPOS_PROTECT(lev);
510  escaped = ESCAPE_P(pppos->in_accm, cur_char);
511  PPPOS_UNPROTECT(lev);
512  /* Handle special characters. */
513  if (escaped) {
514  /* Check for escape sequences. */
515  /* XXX Note that this does not handle an escaped 0x5d character which
516  * would appear as an escape character. Since this is an ASCII ']'
517  * and there is no reason that I know of to escape it, I won't complicate
518  * the code to handle this case. GLL */
519  if (cur_char == PPP_ESCAPE) {
520  pppos->in_escaped = 1;
521  /* Check for the flag character. */
522  } else if (cur_char == PPP_FLAG) {
523  /* If this is just an extra flag character, ignore it. */
524  if (pppos->in_state <= PDADDRESS) {
525  /* ignore it */;
526  /* If we haven't received the packet header, drop what has come in. */
527  } else if (pppos->in_state < PDDATA) {
528  PPPDEBUG(LOG_WARNING,
529  ("pppos_input[%d]: Dropping incomplete packet %d\n",
530  ppp->netif->num, pppos->in_state));
531  LINK_STATS_INC(link.lenerr);
532  pppos_input_drop(pppos);
533  /* If the fcs is invalid, drop the packet. */
534  } else if (pppos->in_fcs != PPP_GOODFCS) {
535  PPPDEBUG(LOG_INFO,
536  ("pppos_input[%d]: Dropping bad fcs 0x%"X16_F" proto=0x%"X16_F"\n",
537  ppp->netif->num, pppos->in_fcs, pppos->in_protocol));
538  /* Note: If you get lots of these, check for UART frame errors or try different baud rate */
539  LINK_STATS_INC(link.chkerr);
540  pppos_input_drop(pppos);
541  /* Otherwise it's a good packet so pass it on. */
542  } else {
543  struct pbuf *inp;
544  /* Trim off the checksum. */
545  if(pppos->in_tail->len > 2) {
546  pppos->in_tail->len -= 2;
547 
548  pppos->in_tail->tot_len = pppos->in_tail->len;
549  if (pppos->in_tail != pppos->in_head) {
550  pbuf_cat(pppos->in_head, pppos->in_tail);
551  }
552  } else {
553  pppos->in_tail->tot_len = pppos->in_tail->len;
554  if (pppos->in_tail != pppos->in_head) {
555  pbuf_cat(pppos->in_head, pppos->in_tail);
556  }
557 
558  pbuf_realloc(pppos->in_head, pppos->in_head->tot_len - 2);
559  }
560 
561  /* Dispatch the packet thereby consuming it. */
562  inp = pppos->in_head;
563  /* Packet consumed, release our references. */
564  pppos->in_head = NULL;
565  pppos->in_tail = NULL;
566 #if IP_FORWARD || LWIP_IPV6_FORWARD
567  /* hide the room for Ethernet forwarding header */
569 #endif /* IP_FORWARD || LWIP_IPV6_FORWARD */
570 #if PPP_INPROC_IRQ_SAFE
571  if(tcpip_callback_with_block(pppos_input_callback, inp, 0) != ERR_OK) {
572  PPPDEBUG(LOG_ERR, ("pppos_input[%d]: tcpip_callback() failed, dropping packet\n", ppp->netif->num));
573  pbuf_free(inp);
574  LINK_STATS_INC(link.drop);
575  MIB2_STATS_NETIF_INC(ppp->netif, ifindiscards);
576  }
577 #else /* PPP_INPROC_IRQ_SAFE */
578  ppp_input(ppp, inp);
579 #endif /* PPP_INPROC_IRQ_SAFE */
580  }
581 
582  /* Prepare for a new packet. */
583  pppos->in_fcs = PPP_INITFCS;
584  pppos->in_state = PDADDRESS;
585  pppos->in_escaped = 0;
586  /* Other characters are usually control characters that may have
587  * been inserted by the physical layer so here we just drop them. */
588  } else {
589  PPPDEBUG(LOG_WARNING,
590  ("pppos_input[%d]: Dropping ACCM char <%d>\n", ppp->netif->num, cur_char));
591  }
592  /* Process other characters. */
593  } else {
594  /* Unencode escaped characters. */
595  if (pppos->in_escaped) {
596  pppos->in_escaped = 0;
597  cur_char ^= PPP_TRANS;
598  }
599 
600  /* Process character relative to current state. */
601  switch(pppos->in_state) {
602  case PDIDLE: /* Idle state - waiting. */
603  /* Drop the character if it's not 0xff
604  * we would have processed a flag character above. */
605  if (cur_char != PPP_ALLSTATIONS) {
606  break;
607  }
608  /* no break */
609  /* Fall through */
610 
611  case PDSTART: /* Process start flag. */
612  /* Prepare for a new packet. */
613  pppos->in_fcs = PPP_INITFCS;
614  /* no break */
615  /* Fall through */
616 
617  case PDADDRESS: /* Process address field. */
618  if (cur_char == PPP_ALLSTATIONS) {
619  pppos->in_state = PDCONTROL;
620  break;
621  }
622  /* no break */
623 
624  /* Else assume compressed address and control fields so
625  * fall through to get the protocol... */
626  case PDCONTROL: /* Process control field. */
627  /* If we don't get a valid control code, restart. */
628  if (cur_char == PPP_UI) {
629  pppos->in_state = PDPROTOCOL1;
630  break;
631  }
632  /* no break */
633 
634 #if 0
635  else {
636  PPPDEBUG(LOG_WARNING,
637  ("pppos_input[%d]: Invalid control <%d>\n", ppp->netif->num, cur_char));
638  pppos->in_state = PDSTART;
639  }
640 #endif
641  case PDPROTOCOL1: /* Process protocol field 1. */
642  /* If the lower bit is set, this is the end of the protocol
643  * field. */
644  if (cur_char & 1) {
645  pppos->in_protocol = cur_char;
646  pppos->in_state = PDDATA;
647  } else {
648  pppos->in_protocol = (u16_t)cur_char << 8;
649  pppos->in_state = PDPROTOCOL2;
650  }
651  break;
652  case PDPROTOCOL2: /* Process protocol field 2. */
653  pppos->in_protocol |= cur_char;
654  pppos->in_state = PDDATA;
655  break;
656  case PDDATA: /* Process data byte. */
657  /* Make space to receive processed data. */
658  if (pppos->in_tail == NULL || pppos->in_tail->len == PBUF_POOL_BUFSIZE) {
659  u16_t pbuf_alloc_len;
660  if (pppos->in_tail != NULL) {
661  pppos->in_tail->tot_len = pppos->in_tail->len;
662  if (pppos->in_tail != pppos->in_head) {
663  pbuf_cat(pppos->in_head, pppos->in_tail);
664  /* give up the in_tail reference now */
665  pppos->in_tail = NULL;
666  }
667  }
668  /* If we haven't started a packet, we need a packet header. */
669  pbuf_alloc_len = 0;
670 #if IP_FORWARD || LWIP_IPV6_FORWARD
671  /* If IP forwarding is enabled we are reserving PBUF_LINK_ENCAPSULATION_HLEN
672  * + PBUF_LINK_HLEN bytes so the packet is being allocated with enough header
673  * space to be forwarded (to Ethernet for example).
674  */
675  if (pppos->in_head == NULL) {
676  pbuf_alloc_len = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN;
677  }
678 #endif /* IP_FORWARD || LWIP_IPV6_FORWARD */
679  next_pbuf = pbuf_alloc(PBUF_RAW, pbuf_alloc_len, PBUF_POOL);
680  if (next_pbuf == NULL) {
681  /* No free buffers. Drop the input packet and let the
682  * higher layers deal with it. Continue processing
683  * the received pbuf chain in case a new packet starts. */
684  PPPDEBUG(LOG_ERR, ("pppos_input[%d]: NO FREE PBUFS!\n", ppp->netif->num));
685  LINK_STATS_INC(link.memerr);
686  pppos_input_drop(pppos);
687  pppos->in_state = PDSTART; /* Wait for flag sequence. */
688  break;
689  }
690  if (pppos->in_head == NULL) {
691  u8_t *payload = ((u8_t*)next_pbuf->payload) + pbuf_alloc_len;
692 #if PPP_INPROC_IRQ_SAFE
693  ((struct pppos_input_header*)payload)->ppp = ppp;
694  payload += sizeof(struct pppos_input_header);
695  next_pbuf->len += sizeof(struct pppos_input_header);
696 #endif /* PPP_INPROC_IRQ_SAFE */
697  next_pbuf->len += sizeof(pppos->in_protocol);
698  *(payload++) = pppos->in_protocol >> 8;
699  *(payload) = pppos->in_protocol & 0xFF;
700  pppos->in_head = next_pbuf;
701  }
702  pppos->in_tail = next_pbuf;
703  }
704  /* Load character into buffer. */
705  ((u8_t*)pppos->in_tail->payload)[pppos->in_tail->len++] = cur_char;
706  break;
707  default:
708  break;
709  }
710 
711  /* update the frame check sequence number. */
712  pppos->in_fcs = PPP_FCS(pppos->in_fcs, cur_char);
713  }
714  } /* while (l-- > 0), all bytes processed */
715 }
716 
717 #if PPP_INPROC_IRQ_SAFE
718 /* PPPoS input callback using one input pointer
719  */
720 static void pppos_input_callback(void *arg) {
721  struct pbuf *pb = (struct pbuf*)arg;
722  ppp_pcb *ppp;
723 
724  ppp = ((struct pppos_input_header*)pb->payload)->ppp;
725  if(pbuf_header(pb, -(s16_t)sizeof(struct pppos_input_header))) {
726  LWIP_ASSERT("pbuf_header failed\n", 0);
727  goto drop;
728  }
729 
730  /* Dispatch the packet thereby consuming it. */
731  ppp_input(ppp, pb);
732  return;
733 
734 drop:
735  LINK_STATS_INC(link.drop);
736  MIB2_STATS_NETIF_INC(ppp->netif, ifindiscards);
737  pbuf_free(pb);
738 }
739 #endif /* PPP_INPROC_IRQ_SAFE */
740 
741 static void
742 pppos_send_config(ppp_pcb *ppp, void *ctx, u32_t accm, int pcomp, int accomp)
743 {
744  int i;
745  pppos_pcb *pppos = (pppos_pcb *)ctx;
746  LWIP_UNUSED_ARG(ppp);
747 
748  pppos->pcomp = pcomp;
749  pppos->accomp = accomp;
750 
751  /* Load the ACCM bits for the 32 control codes. */
752  for (i = 0; i < 32/8; i++) {
753  pppos->out_accm[i] = (u8_t)((accm >> (8 * i)) & 0xFF);
754  }
755 
756  PPPDEBUG(LOG_INFO, ("pppos_send_config[%d]: out_accm=%X %X %X %X\n",
757  pppos->ppp->netif->num,
758  pppos->out_accm[0], pppos->out_accm[1], pppos->out_accm[2], pppos->out_accm[3]));
759 }
760 
761 static void
762 pppos_recv_config(ppp_pcb *ppp, void *ctx, u32_t accm, int pcomp, int accomp)
763 {
764  int i;
765  pppos_pcb *pppos = (pppos_pcb *)ctx;
766  PPPOS_DECL_PROTECT(lev);
767  LWIP_UNUSED_ARG(ppp);
768  LWIP_UNUSED_ARG(pcomp);
769  LWIP_UNUSED_ARG(accomp);
770 
771  /* Load the ACCM bits for the 32 control codes. */
772  PPPOS_PROTECT(lev);
773  for (i = 0; i < 32 / 8; i++) {
774  pppos->in_accm[i] = (u8_t)(accm >> (i * 8));
775  }
776  PPPOS_UNPROTECT(lev);
777 
778  PPPDEBUG(LOG_INFO, ("pppos_recv_config[%d]: in_accm=%X %X %X %X\n",
779  pppos->ppp->netif->num,
780  pppos->in_accm[0], pppos->in_accm[1], pppos->in_accm[2], pppos->in_accm[3]));
781 }
782 
783 /*
784  * Drop the input packet.
785  */
786 static void
787 pppos_input_free_current_packet(pppos_pcb *pppos)
788 {
789  if (pppos->in_head != NULL) {
790  if (pppos->in_tail && (pppos->in_tail != pppos->in_head)) {
791  pbuf_free(pppos->in_tail);
792  }
793  pbuf_free(pppos->in_head);
794  pppos->in_head = NULL;
795  }
796  pppos->in_tail = NULL;
797 }
798 
799 /*
800  * Drop the input packet and increase error counters.
801  */
802 static void
803 pppos_input_drop(pppos_pcb *pppos)
804 {
805  if (pppos->in_head != NULL) {
806 #if 0
807  PPPDEBUG(LOG_INFO, ("pppos_input_drop: %d:%.*H\n", pppos->in_head->len, min(60, pppos->in_head->len * 2), pppos->in_head->payload));
808 #endif
809  PPPDEBUG(LOG_INFO, ("pppos_input_drop: pbuf len=%d, addr %p\n", pppos->in_head->len, (void*)pppos->in_head));
810  }
811  pppos_input_free_current_packet(pppos);
812 #if VJ_SUPPORT && LWIP_TCP
813  vj_uncompress_err(&pppos->ppp->vj_comp);
814 #endif /* VJ_SUPPORT && LWIP_TCP */
815 
816  LINK_STATS_INC(link.drop);
817  MIB2_STATS_NETIF_INC(pppos->ppp->netif, ifindiscards);
818 }
819 
820 /*
821  * pppos_output_append - append given character to end of given pbuf.
822  * If out_accm is not 0 and the character needs to be escaped, do so.
823  * If pbuf is full, send the pbuf and reuse it.
824  * Return the current pbuf.
825  */
826 static err_t
827 pppos_output_append(pppos_pcb *pppos, err_t err, struct pbuf *nb, u8_t c, u8_t accm, u16_t *fcs)
828 {
829  if (err != ERR_OK) {
830  return err;
831  }
832 
833  /* Make sure there is room for the character and an escape code.
834  * Sure we don't quite fill the buffer if the character doesn't
835  * get escaped but is one character worth complicating this? */
836  if ((PBUF_POOL_BUFSIZE - nb->len) < 2) {
837  u32_t l = pppos->output_cb(pppos->ppp, (u8_t*)nb->payload, nb->len, pppos->ppp->ctx_cb);
838  if (l != nb->len) {
839  return ERR_IF;
840  }
841  nb->len = 0;
842  }
843 
844  /* Update FCS before checking for special characters. */
845  if (fcs) {
846  *fcs = PPP_FCS(*fcs, c);
847  }
848 
849  /* Copy to output buffer escaping special characters. */
850  if (accm && ESCAPE_P(pppos->out_accm, c)) {
851  *((u8_t*)nb->payload + nb->len++) = PPP_ESCAPE;
852  *((u8_t*)nb->payload + nb->len++) = c ^ PPP_TRANS;
853  } else {
854  *((u8_t*)nb->payload + nb->len++) = c;
855  }
856 
857  return ERR_OK;
858 }
859 
860 static err_t
861 pppos_output_last(pppos_pcb *pppos, err_t err, struct pbuf *nb, u16_t *fcs)
862 {
863  ppp_pcb *ppp = pppos->ppp;
864 
865  /* Add FCS and trailing flag. */
866  err = pppos_output_append(pppos, err, nb, ~(*fcs) & 0xFF, 1, NULL);
867  err = pppos_output_append(pppos, err, nb, (~(*fcs) >> 8) & 0xFF, 1, NULL);
868  err = pppos_output_append(pppos, err, nb, PPP_FLAG, 0, NULL);
869 
870  if (err != ERR_OK) {
871  goto failed;
872  }
873 
874  /* Send remaining buffer if not empty */
875  if (nb->len > 0) {
876  u32_t l = pppos->output_cb(ppp, (u8_t*)nb->payload, nb->len, ppp->ctx_cb);
877  if (l != nb->len) {
878  err = ERR_IF;
879  goto failed;
880  }
881  }
882 
883  pppos->last_xmit = sys_now();
884  MIB2_STATS_NETIF_ADD(ppp->netif, ifoutoctets, nb->tot_len);
885  MIB2_STATS_NETIF_INC(ppp->netif, ifoutucastpkts);
886  LINK_STATS_INC(link.xmit);
887  pbuf_free(nb);
888  return ERR_OK;
889 
890 failed:
891  pppos->last_xmit = 0; /* prepend PPP_FLAG to next packet */
892  LINK_STATS_INC(link.err);
893  LINK_STATS_INC(link.drop);
894  MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards);
895  pbuf_free(nb);
896  return err;
897 }
898 #endif /* PPP_SUPPORT && PPPOS_SUPPORT */
899 
void * state
Definition: netif.h:234
#define PACK_STRUCT_STRUCT
Definition: arch.h:68
signed short s16_t
Definition: cc.h:41
u8_t pbuf_header(struct pbuf *p, s16_t header_size_increment)
Definition: pbuf.c:603
void pbuf_realloc(struct pbuf *p, u16_t new_len)
Definition: pbuf.c:431
err_t tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block)
Definition: tcpip.c:276
#define PACK_STRUCT_FIELD(x)
Definition: arch.h:72
void memp_free(memp_t type, void *mem)
Definition: memp.c:399
u16_t len
Definition: pbuf.h:125
struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
Definition: pbuf.c:199
#define MIB2_STATS_NETIF_ADD(n, x, val)
Definition: snmp.h:122
#define PBUF_POOL_BUFSIZE
Definition: lwipopts.h:105
#define NULL
Definition: usbd_def.h:53
u8_t pbuf_free(struct pbuf *p)
Definition: pbuf.c:652
Definition: pbuf.h:68
unsigned long u32_t
Definition: cc.h:42
err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len)
Definition: pbuf.c:1075
#define PBUF_LINK_ENCAPSULATION_HLEN
Definition: opt.h:1193
#define ERR_OK
Definition: err.h:52
#define ERR_IF
Definition: err.h:73
u16_t tot_len
Definition: pbuf.h:122
Definition: pbuf.h:108
s8_t err_t
Definition: err.h:47
Definition: pbuf.h:90
#define LINK_STATS_INC(x)
Definition: stats.h:318
#define LWIP_ASSERT(message, assertion)
Definition: debug.h:70
Definition: netif.h:182
struct pbuf * next
Definition: pbuf.h:110
#define PACK_STRUCT_BEGIN
Definition: arch.h:60
u32_t sys_now(void)
void pbuf_cat(struct pbuf *h, struct pbuf *t)
Definition: pbuf.c:779
unsigned char u8_t
Definition: cc.h:38
#define PACK_STRUCT_END
Definition: arch.h:64
#define MIB2_STATS_NETIF_INC(n, x)
Definition: snmp.h:121
void * memp_malloc(memp_t type)
Definition: memp.c:303
#define PBUF_LINK_HLEN
Definition: opt.h:1184
#define ERR_MEM
Definition: err.h:53
#define LWIP_UNUSED_ARG(x)
Definition: arch.h:89
unsigned short u16_t
Definition: cc.h:40
void * payload
Definition: pbuf.h:113
#define X16_F
Definition: cc.h:50