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