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