3 * Network Point to Point Protocol over Serial file.
8 * Redistribution and use in source and binary forms, with or without modification,
9 * are permitted provided that the following conditions are met:
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.
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
30 * This file is part of the lwIP TCP/IP stack.
34 #include "netif/ppp/ppp_opts.h"
35 #if PPP_SUPPORT && PPPOS_SUPPORT /* don't build if not configured for use in lwipopts.h */
39 #include "lwip/arch.h"
41 #include "lwip/pbuf.h"
43 #include "lwip/memp.h"
44 #include "lwip/netif.h"
45 #include "lwip/snmp.h"
46 #include "lwip/priv/tcpip_priv.h"
48 #include "lwip/ip4.h" /* for ip4_input() */
50 #include "netif/ppp/ppp_impl.h"
51 #include "netif/ppp/pppos.h"
52 #include "netif/ppp/vj.h"
55 LWIP_MEMPOOL_DECLARE(PPPOS_PCB, MEMP_NUM_PPPOS_INTERFACES, sizeof(pppos_pcb), "PPPOS_PCB")
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);
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);
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);
78 /* Callbacks structure for PPP core */
79 static const struct link_callbacks pppos_callbacks = {
83 #endif /* PPP_SERVER */
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))
98 * FCS lookup table as calculated by genfcstab.
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
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
139 ppp_get_fcs(u8_t byte)
144 for (bit = 8; bit-- > 0; ) {
145 octet = (octet & 0x01) ? ((octet >> 1) ^ PPP_FCS_POLYNOMIAL) : (octet >> 1);
147 return octet & 0xffff;
149 #define PPP_FCS(fcs, c) (((fcs) >> 8) ^ ppp_get_fcs(((fcs) ^ (c)) & 0xff))
150 #endif /* PPP_FCS_TABLE */
153 * Values for FCS calculations.
155 #define PPP_INITFCS 0xffff /* Initial FCS value */
156 #define PPP_GOODFCS 0xf0b8 /* Good final FCS value */
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)
163 #define PPPOS_DECL_PROTECT(lev)
164 #define PPPOS_PROTECT(lev)
165 #define PPPOS_UNPROTECT(lev)
166 #endif /* PPP_INPROC_IRQ_SAFE */
170 * Create a new PPP connection using the given serial I/O device.
172 * Return 0 on success, an error code on failure.
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)
180 pppos = (pppos_pcb *)LWIP_MEMPOOL_ALLOC(PPPOS_PCB);
185 ppp = ppp_new(pppif, &pppos_callbacks, pppos, link_status_cb, ctx_cb);
187 LWIP_MEMPOOL_FREE(PPPOS_PCB, pppos);
191 memset(pppos, 0, sizeof(pppos_pcb));
193 pppos->output_cb = output_cb;
197 /* Called by PPP core */
199 pppos_write(ppp_pcb *ppp, void *ctx, struct pbuf *p)
201 pppos_pcb *pppos = (pppos_pcb *)ctx;
207 LWIP_UNUSED_ARG(ppp);
209 /* Grab an output buffer. */
210 nb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
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);
220 /* If the link has been idle, we'll send a fresh flag character to
221 * flush any noise. */
223 if ((sys_now() - pppos->last_xmit) >= PPP_MAXIDLEFLAG) {
224 err = pppos_output_append(pppos, err, nb, PPP_FLAG, 0, NULL);
227 /* Load output buffer. */
228 fcs_out = PPP_INITFCS;
229 s = (u8_t*)p->payload;
232 err = pppos_output_append(pppos, err, nb, *s++, 1, &fcs_out);
235 err = pppos_output_last(pppos, err, nb, &fcs_out);
237 PPPDEBUG(LOG_INFO, ("pppos_write[%d]: len=%d\n", ppp->netif->num, p->len));
239 PPPDEBUG(LOG_WARNING, ("pppos_write[%d]: output failed len=%d\n", ppp->netif->num, p->len));
245 /* Called by PPP core */
247 pppos_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *pb, u16_t protocol)
249 pppos_pcb *pppos = (pppos_pcb *)ctx;
253 LWIP_UNUSED_ARG(ppp);
255 /* Grab an output buffer. */
256 nb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
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);
265 /* If the link has been idle, we'll send a fresh flag character to
266 * flush any noise. */
268 if ((sys_now() - pppos->last_xmit) >= PPP_MAXIDLEFLAG) {
269 err = pppos_output_append(pppos, err, nb, PPP_FLAG, 0, NULL);
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);
277 if (!pppos->pcomp || protocol > 0xFF) {
278 err = pppos_output_append(pppos, err, nb, (protocol >> 8) & 0xFF, 1, &fcs_out);
280 err = pppos_output_append(pppos, err, nb, protocol & 0xFF, 1, &fcs_out);
283 for(p = pb; p; p = p->next) {
285 u8_t *s = (u8_t*)p->payload;
288 err = pppos_output_append(pppos, err, nb, *s++, 1, &fcs_out);
292 err = pppos_output_last(pppos, err, nb, &fcs_out);
294 PPPDEBUG(LOG_INFO, ("pppos_netif_output[%d]: proto=0x%"X16_F", len = %d\n", ppp->netif->num, protocol, pb->tot_len));
296 PPPDEBUG(LOG_WARNING, ("pppos_netif_output[%d]: output failed proto=0x%"X16_F", len = %d\n", ppp->netif->num, protocol, pb->tot_len));
302 pppos_connect(ppp_pcb *ppp, void *ctx)
304 pppos_pcb *pppos = (pppos_pcb *)ctx;
305 PPPOS_DECL_PROTECT(lev);
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 */
312 /* reset PPPoS control block to its initial state */
313 memset(&pppos->last_xmit, 0, sizeof(pppos_pcb) - offsetof(pppos_pcb, last_xmit));
316 * Default the in and out accm so that escape and flag characters
317 * are always escaped.
319 pppos->in_accm[15] = 0x60; /* no need to protect since RX is not running */
320 pppos->out_accm[15] = 0x60;
323 PPPOS_UNPROTECT(lev);
326 * Start the connection and handle incoming events (packet or timeout).
328 PPPDEBUG(LOG_INFO, ("pppos_connect: unit %d: connecting\n", ppp->netif->num));
329 ppp_start(ppp); /* notify upper layers */
334 pppos_listen(ppp_pcb *ppp, void *ctx)
336 pppos_pcb *pppos = (pppos_pcb *)ctx;
337 PPPOS_DECL_PROTECT(lev);
339 #if PPP_INPROC_IRQ_SAFE
340 /* input pbuf left over from last session? */
341 pppos_input_free_current_packet(pppos);
342 #endif /* PPP_INPROC_IRQ_SAFE */
344 /* reset PPPoS control block to its initial state */
345 memset(&pppos->last_xmit, 0, sizeof(pppos_pcb) - offsetof(pppos_pcb, last_xmit));
348 * Default the in and out accm so that escape and flag characters
349 * are always escaped.
351 pppos->in_accm[15] = 0x60; /* no need to protect since RX is not running */
352 pppos->out_accm[15] = 0x60;
355 PPPOS_UNPROTECT(lev);
358 * Wait for something to happen.
360 PPPDEBUG(LOG_INFO, ("pppos_listen: unit %d: listening\n", ppp->netif->num));
361 ppp_start(ppp); /* notify upper layers */
363 #endif /* PPP_SERVER */
366 pppos_disconnect(ppp_pcb *ppp, void *ctx)
368 pppos_pcb *pppos = (pppos_pcb *)ctx;
369 PPPOS_DECL_PROTECT(lev);
373 PPPOS_UNPROTECT(lev);
375 /* If PPP_INPROC_IRQ_SAFE is used we cannot call
376 * pppos_input_free_current_packet() here because
377 * rx IRQ might still call pppos_input().
379 #if !PPP_INPROC_IRQ_SAFE
380 /* input pbuf left ? */
381 pppos_input_free_current_packet(pppos);
382 #endif /* !PPP_INPROC_IRQ_SAFE */
384 ppp_link_end(ppp); /* notify upper layers */
388 pppos_destroy(ppp_pcb *ppp, void *ctx)
390 pppos_pcb *pppos = (pppos_pcb *)ctx;
391 LWIP_UNUSED_ARG(ppp);
393 #if PPP_INPROC_IRQ_SAFE
394 /* input pbuf left ? */
395 pppos_input_free_current_packet(pppos);
396 #endif /* PPP_INPROC_IRQ_SAFE */
398 LWIP_MEMPOOL_FREE(PPPOS_PCB, pppos);
402 #if !NO_SYS && !PPP_INPROC_IRQ_SAFE
403 /** Pass received raw characters to PPPoS to be decoded through lwIP TCPIP thread.
405 * @param ppp PPP descriptor index, returned by pppos_create()
406 * @param s received data
407 * @param l length of received data
410 pppos_input_tcpip(ppp_pcb *ppp, u8_t *s, int l)
415 p = pbuf_alloc(PBUF_RAW, l, PBUF_POOL);
421 err = tcpip_inpkt(p, ppp_netif(ppp), pppos_input_sys);
428 /* called from TCPIP thread */
429 err_t pppos_input_sys(struct pbuf *p, struct netif *inp) {
430 ppp_pcb *ppp = (ppp_pcb*)inp->state;
433 for (n = p; n; n = n->next) {
434 pppos_input(ppp, (u8_t*)n->payload, n->len);
439 #endif /* !NO_SYS && !PPP_INPROC_IRQ_SAFE */
441 /** PPPoS input helper struct, must be packed since it is stored
442 * to pbuf->payload, which might be unaligned. */
443 #if PPP_INPROC_IRQ_SAFE
444 #ifdef PACK_STRUCT_USE_INCLUDES
445 # include "arch/bpstruct.h"
448 struct pppos_input_header {
449 PACK_STRUCT_FIELD(ppp_pcb *ppp);
450 } PACK_STRUCT_STRUCT;
452 #ifdef PACK_STRUCT_USE_INCLUDES
453 # include "arch/epstruct.h"
455 #endif /* PPP_INPROC_IRQ_SAFE */
457 /** Pass received raw characters to PPPoS to be decoded.
459 * @param ppp PPP descriptor index, returned by pppos_create()
460 * @param s received data
461 * @param l length of received data
464 pppos_input(ppp_pcb *ppp, u8_t *s, int l)
466 pppos_pcb *pppos = (pppos_pcb *)ppp->link_ctx_cb;
467 struct pbuf *next_pbuf;
470 PPPOS_DECL_PROTECT(lev);
472 PPPDEBUG(LOG_DEBUG, ("pppos_input[%d]: got %d bytes\n", ppp->netif->num, l));
477 /* ppp_input can disconnect the interface, we need to abort to prevent a memory
478 * leak if there are remaining bytes because pppos_connect and pppos_listen
479 * functions expect input buffer to be free. Furthermore there are no real
480 * reason to continue reading bytes if we are disconnected.
483 PPPOS_UNPROTECT(lev);
486 escaped = ESCAPE_P(pppos->in_accm, cur_char);
487 PPPOS_UNPROTECT(lev);
488 /* Handle special characters. */
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) {
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) {
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. */
520 /* Trim off the checksum. */
521 if(pppos->in_tail->len > 2) {
522 pppos->in_tail->len -= 2;
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);
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);
534 pbuf_realloc(pppos->in_head, pppos->in_head->tot_len - 2);
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));
550 LINK_STATS_INC(link.drop);
551 MIB2_STATS_NETIF_INC(ppp->netif, ifindiscards);
553 #else /* PPP_INPROC_IRQ_SAFE */
555 #endif /* PPP_INPROC_IRQ_SAFE */
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. */
565 PPPDEBUG(LOG_WARNING,
566 ("pppos_input[%d]: Dropping ACCM char <%d>\n", ppp->netif->num, cur_char));
568 /* Process other characters. */
570 /* Unencode escaped characters. */
571 if (pppos->in_escaped) {
572 pppos->in_escaped = 0;
573 cur_char ^= PPP_TRANS;
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) {
587 case PDSTART: /* Process start flag. */
588 /* Prepare for a new packet. */
589 pppos->in_fcs = PPP_INITFCS;
593 case PDADDRESS: /* Process address field. */
594 if (cur_char == PPP_ALLSTATIONS) {
595 pppos->in_state = PDCONTROL;
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;
612 PPPDEBUG(LOG_WARNING,
613 ("pppos_input[%d]: Invalid control <%d>\n", ppp->netif->num, cur_char));
614 pppos->in_state = PDSTART;
617 case PDPROTOCOL1: /* Process protocol field 1. */
618 /* If the lower bit is set, this is the end of the protocol
621 pppos->in_protocol = cur_char;
622 pppos->in_state = PDDATA;
624 pppos->in_protocol = (u16_t)cur_char << 8;
625 pppos->in_state = PDPROTOCOL2;
628 case PDPROTOCOL2: /* Process protocol field 2. */
629 pppos->in_protocol |= cur_char;
630 pppos->in_state = PDDATA;
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;
644 /* If we haven't started a packet, we need a packet header. */
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).
651 if (pppos->in_head == NULL) {
652 pbuf_alloc_len = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN;
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. */
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;
678 pppos->in_tail = next_pbuf;
680 /* Load character into buffer. */
681 ((u8_t*)pppos->in_tail->payload)[pppos->in_tail->len++] = cur_char;
687 /* update the frame check sequence number. */
688 pppos->in_fcs = PPP_FCS(pppos->in_fcs, cur_char);
690 } /* while (l-- > 0), all bytes processed */
693 #if PPP_INPROC_IRQ_SAFE
694 /* PPPoS input callback using one input pointer
696 static void pppos_input_callback(void *arg) {
697 struct pbuf *pb = (struct pbuf*)arg;
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);
706 /* Dispatch the packet thereby consuming it. */
711 LINK_STATS_INC(link.drop);
712 MIB2_STATS_NETIF_INC(ppp->netif, ifindiscards);
715 #endif /* PPP_INPROC_IRQ_SAFE */
718 pppos_send_config(ppp_pcb *ppp, void *ctx, u32_t accm, int pcomp, int accomp)
721 pppos_pcb *pppos = (pppos_pcb *)ctx;
722 LWIP_UNUSED_ARG(ppp);
724 pppos->pcomp = pcomp;
725 pppos->accomp = accomp;
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);
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]));
738 pppos_recv_config(ppp_pcb *ppp, void *ctx, u32_t accm, int pcomp, int accomp)
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);
747 /* Load the ACCM bits for the 32 control codes. */
749 for (i = 0; i < 32 / 8; i++) {
750 pppos->in_accm[i] = (u8_t)(accm >> (i * 8));
752 PPPOS_UNPROTECT(lev);
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]));
760 * Drop the input packet.
763 pppos_input_free_current_packet(pppos_pcb *pppos)
765 if (pppos->in_head != NULL) {
766 if (pppos->in_tail && (pppos->in_tail != pppos->in_head)) {
767 pbuf_free(pppos->in_tail);
769 pbuf_free(pppos->in_head);
770 pppos->in_head = NULL;
772 pppos->in_tail = NULL;
776 * Drop the input packet and increase error counters.
779 pppos_input_drop(pppos_pcb *pppos)
781 if (pppos->in_head != NULL) {
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));
785 PPPDEBUG(LOG_INFO, ("pppos_input_drop: pbuf len=%d, addr %p\n", pppos->in_head->len, (void*)pppos->in_head));
787 pppos_input_free_current_packet(pppos);
789 vj_uncompress_err(&pppos->ppp->vj_comp);
790 #endif /* VJ_SUPPORT */
792 LINK_STATS_INC(link.drop);
793 MIB2_STATS_NETIF_INC(pppos->ppp->netif, ifindiscards);
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.
803 pppos_output_append(pppos_pcb *pppos, err_t err, struct pbuf *nb, u8_t c, u8_t accm, u16_t *fcs)
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);
820 /* Update FCS before checking for special characters. */
822 *fcs = PPP_FCS(*fcs, c);
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;
830 *((u8_t*)nb->payload + nb->len++) = c;
837 pppos_output_last(pppos_pcb *pppos, err_t err, struct pbuf *nb, u16_t *fcs)
839 ppp_pcb *ppp = pppos->ppp;
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);
850 /* Send remaining buffer if not empty */
852 u32_t l = pppos->output_cb(ppp, (u8_t*)nb->payload, nb->len, ppp->ctx_cb);
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);
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);
875 #endif /* PPP_SUPPORT && PPPOS_SUPPORT */