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