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