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