1 /*****************************************************************************
2 * ppp.c - Network Point to Point Protocol program file.
4 * Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
5 * portions Copyright (c) 1997 by Global Election Systems Inc.
7 * The authors hereby grant permission to use, copy, modify, distribute,
8 * and license this software and its documentation for any purpose, provided
9 * that existing copyright notices are retained in all copies and that this
10 * notice and the following disclaimer are included verbatim in any
11 * distributions. No written agreement, license, or royalty fee is required
12 * for any of the authorized uses.
14 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 ******************************************************************************
28 * 03-01-01 Marc Boucher <marc@mbsi.ca>
30 * 97-11-05 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
32 *****************************************************************************/
35 * ppp_defs.h - PPP definitions.
37 * if_pppvar.h - private structures and declarations for PPP.
39 * Copyright (c) 1994 The Australian National University.
40 * All rights reserved.
42 * Permission to use, copy, modify, and distribute this software and its
43 * documentation is hereby granted, provided that the above copyright
44 * notice appears in all copies. This software is provided without any
45 * warranty, express or implied. The Australian National University
46 * makes no representations about the suitability of this software for
49 * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
50 * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
51 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
52 * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
55 * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
56 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
57 * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
58 * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
59 * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
64 * if_ppp.h - Point-to-Point Protocol definitions.
66 * Copyright (c) 1989 Carnegie Mellon University.
67 * All rights reserved.
69 * Redistribution and use in source and binary forms are permitted
70 * provided that the above copyright notice and this paragraph are
71 * duplicated in all such forms and that any documentation,
72 * advertising materials, and other materials related to such
73 * distribution and use acknowledge that the software was developed
74 * by Carnegie Mellon University. The name of the
75 * University may not be used to endorse or promote products derived
76 * from this software without specific prior written permission.
77 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
78 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
79 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
84 #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
86 #include "lwip/ip.h" /* for ip_input() */
95 #endif /* PAP_SUPPORT */
98 #endif /* CHAP_SUPPORT */
105 #endif /* VJ_SUPPORT */
107 #include "netif/ppp_oe.h"
108 #endif /* PPPOE_SUPPORT */
110 #include "lwip/tcpip.h"
111 #include "lwip/api.h"
112 #include "lwip/snmp.h"
116 /*************************/
117 /*** LOCAL DEFINITIONS ***/
118 /*************************/
120 /** PPP_INPROC_MULTITHREADED==1 call pppInput using tcpip_callback().
121 * Set this to 0 if pppInProc is called inside tcpip_thread or with NO_SYS==1.
122 * Default is 1 for NO_SYS==0 (multithreaded) and 0 for NO_SYS==1 (single-threaded).
124 #ifndef PPP_INPROC_MULTITHREADED
125 #define PPP_INPROC_MULTITHREADED (NO_SYS==0)
128 /** PPP_INPROC_OWNTHREAD==1: start a dedicated RX thread per PPP session.
129 * Default is 0: call pppos_input() for received raw characters, charcater
130 * reception is up to the port */
131 #ifndef PPP_INPROC_OWNTHREAD
132 #define PPP_INPROC_OWNTHREAD PPP_INPROC_MULTITHREADED
135 #if PPP_INPROC_OWNTHREAD && !PPP_INPROC_MULTITHREADED
136 #error "PPP_INPROC_OWNTHREAD needs PPP_INPROC_MULTITHREADED==1"
140 * The basic PPP frame.
142 #define PPP_ADDRESS(p) (((u_char *)(p))[0])
143 #define PPP_CONTROL(p) (((u_char *)(p))[1])
144 #define PPP_PROTOCOL(p) ((((u_char *)(p))[2] << 8) + ((u_char *)(p))[3])
146 /* PPP packet parser states. Current state indicates operation yet to be
149 PDIDLE = 0, /* Idle state - waiting. */
150 PDSTART, /* Process start flag. */
151 PDADDRESS, /* Process address field. */
152 PDCONTROL, /* Process control field. */
153 PDPROTOCOL1, /* Process protocol field 1. */
154 PDPROTOCOL2, /* Process protocol field 2. */
155 PDDATA /* Process data byte. */
158 #define ESCAPE_P(accm, c) ((accm)[(c) >> 3] & pppACCMMask[c & 0x07])
160 /************************/
161 /*** LOCAL DATA TYPES ***/
162 /************************/
164 /** RX buffer size: this may be configured smaller! */
165 #ifndef PPPOS_RX_BUFSIZE
166 #define PPPOS_RX_BUFSIZE (PPP_MRU + PPP_HDRLEN)
169 typedef struct PPPControlRx_s {
170 /** unit number / ppp descriptor */
172 /** the rx file descriptor */
174 /** receive buffer - encoded data is stored here */
175 u_char rxbuf[PPPOS_RX_BUFSIZE];
177 /* The input packet. */
178 struct pbuf *inHead, *inTail;
181 u16_t inProtocol; /* The input protocol code. */
182 u16_t inFCS; /* Input Frame Check Sequence value. */
183 #endif /* PPPOS_SUPPORT */
184 PPPDevStates inState; /* The input process state. */
185 char inEscaped; /* Escape next character. */
186 ext_accm inACCM; /* Async-Ctl-Char-Map for input. */
190 * PPP interface control block.
192 typedef struct PPPControl_s {
194 char openFlag; /* True when in use. */
197 struct pppoe_softc *pppoe_sc;
198 #endif /* PPPOE_SUPPORT */
199 int if_up; /* True when the interface is up. */
200 int errCode; /* Code indicating why interface is down. */
202 sio_fd_t fd; /* File device ID of port. */
203 #endif /* PPPOS_SUPPORT */
204 u16_t mtu; /* Peer's mru */
205 int pcomp; /* Does peer accept protocol compression? */
206 int accomp; /* Does peer accept addr/ctl compression? */
207 u_long lastXMit; /* Time of last transmission. */
208 ext_accm outACCM; /* Async-Ctl-Char-Map for output. */
209 #if PPPOS_SUPPORT && VJ_SUPPORT
210 int vjEnabled; /* Flag indicating VJ compression enabled. */
211 struct vjcompress vjComp; /* Van Jacobson compression header. */
212 #endif /* PPPOS_SUPPORT && VJ_SUPPORT */
216 struct ppp_addrs addrs;
218 void (*linkStatusCB)(void *ctx, int errCode, void *arg);
229 int protocol; /* PPP procotol, e.g. PPP_IP */
235 /***********************************/
236 /*** LOCAL FUNCTION DECLARATIONS ***/
237 /***********************************/
239 #if PPP_INPROC_OWNTHREAD
240 static void pppInputThread(void *arg);
241 #endif /* PPP_INPROC_OWNTHREAD */
242 static void pppDrop(PPPControlRx *pcrx);
243 static void pppInProc(PPPControlRx *pcrx, u_char *s, int l);
244 #endif /* PPPOS_SUPPORT */
247 /******************************/
248 /*** PUBLIC DATA STRUCTURES ***/
249 /******************************/
252 static PPPControl pppControl[NUM_PPP]; /* The PPP interface control blocks. */
255 * PPP Data Link Layer "protocol" table.
256 * One entry per supported protocol.
257 * The last entry must be NULL.
259 struct protent *ppp_protocols[] = {
263 #endif /* PAP_SUPPORT */
266 #endif /* CHAP_SUPPORT */
269 #endif /* CBCP_SUPPORT */
273 #endif /* CCP_SUPPORT */
279 * Buffers for outgoing packets. This must be accessed only from the appropriate
280 * PPP task so that it doesn't need to be protected to avoid collisions.
282 u_char outpacket_buf[NUM_PPP][PPP_MRU+PPP_HDRLEN];
285 /*****************************/
286 /*** LOCAL DATA STRUCTURES ***/
287 /*****************************/
291 * FCS lookup table as calculated by genfcstab.
292 * @todo: smaller, slower implementation for lower memory footprint?
294 static const u_short fcstab[256] = {
295 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
296 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
297 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
298 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
299 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
300 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
301 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
302 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
303 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
304 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
305 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
306 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
307 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
308 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
309 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
310 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
311 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
312 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
313 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
314 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
315 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
316 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
317 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
318 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
319 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
320 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
321 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
322 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
323 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
324 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
325 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
326 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
329 /* PPP's Asynchronous-Control-Character-Map. The mask array is used
330 * to select the specific bit for a character. */
331 static u_char pppACCMMask[] = {
342 /** Wake up the task blocked in reading from serial line (if any) */
344 pppRecvWakeup(int pd)
346 PPPDEBUG(LOG_DEBUG, ("pppRecvWakeup: unit %d\n", pd));
347 sio_read_abort(pppControl[pd].fd);
349 #endif /* PPPOS_SUPPORT */
352 pppLinkTerminated(int pd)
354 PPPDEBUG(LOG_DEBUG, ("pppLinkTerminated: unit %d\n", pd));
357 if (pppControl[pd].ethif) {
358 pppoe_disconnect(pppControl[pd].pppoe_sc);
360 #endif /* PPPOE_SUPPORT */
365 pc = &pppControl[pd];
366 pppDrop(&pc->rx); /* bug fix #17726 */
368 PPPDEBUG(LOG_DEBUG, ("pppLinkTerminated: unit %d: linkStatusCB=%p errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));
369 if (pc->linkStatusCB) {
370 pc->linkStatusCB(pc->linkStatusCtx, pc->errCode ? pc->errCode : PPPERR_PROTOCOL, NULL);
373 pc->openFlag = 0;/**/
374 #endif /* PPPOS_SUPPORT */
376 PPPDEBUG(LOG_DEBUG, ("pppLinkTerminated: finished.\n"));
382 PPPDEBUG(LOG_DEBUG, ("pppLinkDown: unit %d\n", pd));
385 if (pppControl[pd].ethif) {
386 pppoe_disconnect(pppControl[pd].pppoe_sc);
388 #endif /* PPPOE_SUPPORT */
392 #endif /* PPPOS_SUPPORT */
396 /** Initiate LCP open request */
400 PPPDEBUG(LOG_DEBUG, ("pppStart: unit %d\n", pd));
402 lcp_open(pd); /* Start protocol */
403 PPPDEBUG(LOG_DEBUG, ("pppStart: finished\n"));
406 /** LCP close request */
410 PPPDEBUG(LOG_DEBUG, ("pppStop: unit %d\n", pd));
411 lcp_close(pd, "User request");
414 /** Called when carrier/link is lost */
418 PPPDEBUG(LOG_DEBUG, ("pppHupCB: unit %d\n", pd));
423 /***********************************/
424 /*** PUBLIC FUNCTION DEFINITIONS ***/
425 /***********************************/
426 /* Initialize the PPP subsystem. */
428 struct ppp_settings ppp_settings;
433 struct protent *protp;
436 memset(&ppp_settings, 0, sizeof(ppp_settings));
437 ppp_settings.usepeerdns = 1;
438 pppSetAuth(PPPAUTHTYPE_NONE, NULL, NULL);
442 subnetMask = PP_HTONL(0xffffff00);
444 for (i = 0; i < NUM_PPP; i++) {
445 /* Initialize each protocol to the standard option set. */
446 for (j = 0; (protp = ppp_protocols[j]) != NULL; ++j) {
453 pppSetAuth(enum pppAuthType authType, const char *user, const char *passwd)
456 case PPPAUTHTYPE_NONE:
458 #ifdef LWIP_PPP_STRICT_PAP_REJECT
459 ppp_settings.refuse_pap = 1;
460 #else /* LWIP_PPP_STRICT_PAP_REJECT */
461 /* some providers request pap and accept an empty login/pw */
462 ppp_settings.refuse_pap = 0;
463 #endif /* LWIP_PPP_STRICT_PAP_REJECT */
464 ppp_settings.refuse_chap = 1;
467 case PPPAUTHTYPE_ANY:
468 /* Warning: Using PPPAUTHTYPE_ANY might have security consequences.
471 * In practice, within or associated with each PPP server, there is a
472 * database which associates "user" names with authentication
473 * information ("secrets"). It is not anticipated that a particular
474 * named user would be authenticated by multiple methods. This would
475 * make the user vulnerable to attacks which negotiate the least secure
476 * method from among a set (such as PAP rather than CHAP). If the same
477 * secret was used, PAP would reveal the secret to be used later with
480 * Instead, for each user name there should be an indication of exactly
481 * one method used to authenticate that user name. If a user needs to
482 * make use of different authentication methods under different
483 * circumstances, then distinct user names SHOULD be employed, each of
484 * which identifies exactly one authentication method.
487 ppp_settings.refuse_pap = 0;
488 ppp_settings.refuse_chap = 0;
491 case PPPAUTHTYPE_PAP:
492 ppp_settings.refuse_pap = 0;
493 ppp_settings.refuse_chap = 1;
496 case PPPAUTHTYPE_CHAP:
497 ppp_settings.refuse_pap = 1;
498 ppp_settings.refuse_chap = 0;
503 strncpy(ppp_settings.user, user, sizeof(ppp_settings.user)-1);
504 ppp_settings.user[sizeof(ppp_settings.user)-1] = '\0';
506 ppp_settings.user[0] = '\0';
510 strncpy(ppp_settings.passwd, passwd, sizeof(ppp_settings.passwd)-1);
511 ppp_settings.passwd[sizeof(ppp_settings.passwd)-1] = '\0';
513 ppp_settings.passwd[0] = '\0';
518 /** Open a new PPP connection using the given I/O device.
519 * This initializes the PPP control block but does not
520 * attempt to negotiate the LCP session. If this port
521 * connects to a modem, the modem connection must be
522 * established before calling this.
523 * Return a new PPP connection descriptor on success or
524 * an error code (negative) on failure.
526 * pppOpen() is directly defined to this function.
529 pppOverSerialOpen(sio_fd_t fd, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx)
534 if (linkStatusCB == NULL) {
535 /* PPP is single-threaded: without a callback,
536 * there is no way to know when the link is up. */
540 /* Find a free PPP session descriptor. */
541 for (pd = 0; pd < NUM_PPP && pppControl[pd].openFlag != 0; pd++);
546 pc = &pppControl[pd];
547 /* @todo: is this correct or do I overwrite something? */
548 memset(pc, 0, sizeof(PPPControl));
556 vj_compress_init(&pc->vjComp);
557 #endif /* VJ_SUPPORT */
560 * Default the in and out accm so that escape and flag characters
561 * are always escaped.
563 pc->rx.inACCM[15] = 0x60; /* no need to protect since RX is not running */
564 pc->outACCM[15] = 0x60;
566 pc->linkStatusCB = linkStatusCB;
567 pc->linkStatusCtx = linkStatusCtx;
570 * Start the connection and handle incoming events (packet or timeout).
572 PPPDEBUG(LOG_INFO, ("pppOverSerialOpen: unit %d: Connecting\n", pd));
574 #if PPP_INPROC_OWNTHREAD
575 sys_thread_new(PPP_THREAD_NAME, pppInputThread, (void*)&pc->rx, PPP_THREAD_STACKSIZE, PPP_THREAD_PRIO);
581 #endif /* PPPOS_SUPPORT */
584 static void pppOverEthernetLinkStatusCB(int pd, int up);
587 pppOverEthernetClose(int pd)
589 PPPControl* pc = &pppControl[pd];
591 /* *TJL* There's no lcp_deinit */
594 pppoe_destroy(&pc->netif);
597 int pppOverEthernetOpen(struct netif *ethif, const char *service_name, const char *concentrator_name, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx)
602 LWIP_UNUSED_ARG(service_name);
603 LWIP_UNUSED_ARG(concentrator_name);
605 if (linkStatusCB == NULL) {
606 /* PPP is single-threaded: without a callback,
607 * there is no way to know when the link is up. */
611 /* Find a free PPP session descriptor. Critical region? */
612 for (pd = 0; pd < NUM_PPP && pppControl[pd].openFlag != 0; pd++);
616 pc = &pppControl[pd];
617 memset(pc, 0, sizeof(PPPControl));
621 pc->linkStatusCB = linkStatusCB;
622 pc->linkStatusCtx = linkStatusCtx;
624 lcp_wantoptions[pd].mru = PPPOE_MAXMTU;
625 lcp_wantoptions[pd].neg_asyncmap = 0;
626 lcp_wantoptions[pd].neg_pcompression = 0;
627 lcp_wantoptions[pd].neg_accompression = 0;
629 lcp_allowoptions[pd].mru = PPPOE_MAXMTU;
630 lcp_allowoptions[pd].neg_asyncmap = 0;
631 lcp_allowoptions[pd].neg_pcompression = 0;
632 lcp_allowoptions[pd].neg_accompression = 0;
634 if(pppoe_create(ethif, pd, pppOverEthernetLinkStatusCB, &pc->pppoe_sc) != ERR_OK) {
639 pppoe_connect(pc->pppoe_sc);
644 #endif /* PPPOE_SUPPORT */
647 /* Close a PPP connection and release the descriptor.
648 * Any outstanding packets in the queues are dropped.
649 * Return 0 on success, an error code on failure. */
653 PPPControl *pc = &pppControl[pd];
656 PPPDEBUG(LOG_DEBUG, ("pppClose() called\n"));
661 PPPDEBUG(LOG_DEBUG, ("pppClose: unit %d kill_link -> pppStop\n", pd));
662 pc->errCode = PPPERR_USER;
663 /* This will leave us at PHASE_DEAD. */
666 #endif /* PPPOE_SUPPORT */
669 PPPDEBUG(LOG_DEBUG, ("pppClose: unit %d kill_link -> pppStop\n", pd));
670 pc->errCode = PPPERR_USER;
671 /* This will leave us at PHASE_DEAD. */
674 #endif /* PPPOS_SUPPORT */
680 /* This function is called when carrier is lost on the PPP channel. */
685 PPPControl *pc = &pppControl[pd];
687 PPPDEBUG(LOG_DEBUG, ("pppSigHUP: unit %d sig_hup -> pppHupCB\n", pd));
690 #endif /* PPPOE_SUPPORT */
693 PPPDEBUG(LOG_DEBUG, ("pppSigHUP: unit %d sig_hup -> pppHupCB\n", pd));
696 #endif /* PPPOS_SUPPORT */
702 nPut(PPPControl *pc, struct pbuf *nb)
707 for(b = nb; b != NULL; b = b->next) {
708 if((c = sio_write(pc->fd, b->payload, b->len)) != b->len) {
709 PPPDEBUG(LOG_WARNING,
710 ("PPP nPut: incomplete sio_write(fd:%"SZT_F", len:%d, c: 0x%"X8_F") c = %d\n", (size_t)pc->fd, b->len, c, c));
711 LINK_STATS_INC(link.err);
712 pc->lastXMit = 0; /* prepend PPP_FLAG to next packet */
713 snmp_inc_ifoutdiscards(&pc->netif);
719 snmp_add_ifoutoctets(&pc->netif, nb->tot_len);
720 snmp_inc_ifoutucastpkts(&pc->netif);
722 LINK_STATS_INC(link.xmit);
726 * pppAppend - append given character to end of given pbuf. If outACCM
727 * is not NULL and the character needs to be escaped, do so.
728 * If pbuf is full, append another.
729 * Return the current pbuf.
732 pppAppend(u_char c, struct pbuf *nb, ext_accm *outACCM)
734 struct pbuf *tb = nb;
736 /* Make sure there is room for the character and an escape code.
737 * Sure we don't quite fill the buffer if the character doesn't
738 * get escaped but is one character worth complicating this? */
739 /* Note: We assume no packet header. */
740 if (nb && (PBUF_POOL_BUFSIZE - nb->len) < 2) {
741 tb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
745 LINK_STATS_INC(link.memerr);
751 if (outACCM && ESCAPE_P(*outACCM, c)) {
752 *((u_char*)nb->payload + nb->len++) = PPP_ESCAPE;
753 *((u_char*)nb->payload + nb->len++) = c ^ PPP_TRANS;
755 *((u_char*)nb->payload + nb->len++) = c;
761 #endif /* PPPOS_SUPPORT */
765 pppifOutputOverEthernet(int pd, struct pbuf *p)
767 PPPControl *pc = &pppControl[pd];
769 u_short protocol = PPP_IP;
773 /* @todo: try to use pbuf_header() here! */
774 pb = pbuf_alloc(PBUF_LINK, PPPOE_HDRLEN + sizeof(protocol), PBUF_RAM);
776 LINK_STATS_INC(link.memerr);
777 LINK_STATS_INC(link.proterr);
778 snmp_inc_ifoutdiscards(&pc->netif);
782 pbuf_header(pb, -(s16_t)PPPOE_HDRLEN);
784 pc->lastXMit = sys_jiffies();
786 if (!pc->pcomp || protocol > 0xFF) {
787 *((u_char*)pb->payload + i++) = (protocol >> 8) & 0xFF;
789 *((u_char*)pb->payload + i) = protocol & 0xFF;
792 tot_len = pb->tot_len;
794 if(pppoe_xmit(pc->pppoe_sc, pb) != ERR_OK) {
795 LINK_STATS_INC(link.err);
796 snmp_inc_ifoutdiscards(&pc->netif);
797 return PPPERR_DEVICE;
800 snmp_add_ifoutoctets(&pc->netif, tot_len);
801 snmp_inc_ifoutucastpkts(&pc->netif);
802 LINK_STATS_INC(link.xmit);
805 #endif /* PPPOE_SUPPORT */
807 /* Send a packet on the given connection. */
809 pppifOutput(struct netif *netif, struct pbuf *pb, ip_addr_t *ipaddr)
811 int pd = (int)(size_t)netif->state;
812 PPPControl *pc = &pppControl[pd];
814 u_short protocol = PPP_IP;
815 u_int fcsOut = PPP_INITFCS;
816 struct pbuf *headMB = NULL, *tailMB = NULL, *p;
818 #endif /* PPPOS_SUPPORT */
820 LWIP_UNUSED_ARG(ipaddr);
822 /* Validate parameters. */
823 /* We let any protocol value go through - it can't hurt us
824 * and the peer will just drop it if it's not accepting it. */
825 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag || !pb) {
826 PPPDEBUG(LOG_WARNING, ("pppifOutput[%d]: bad parms prot=%d pb=%p\n",
828 LINK_STATS_INC(link.opterr);
829 LINK_STATS_INC(link.drop);
830 snmp_inc_ifoutdiscards(netif);
834 /* Check that the link is up. */
835 if (lcp_phase[pd] == PHASE_DEAD) {
836 PPPDEBUG(LOG_ERR, ("pppifOutput[%d]: link not up\n", pd));
837 LINK_STATS_INC(link.rterr);
838 LINK_STATS_INC(link.drop);
839 snmp_inc_ifoutdiscards(netif);
845 return pppifOutputOverEthernet(pd, pb);
847 #endif /* PPPOE_SUPPORT */
850 /* Grab an output buffer. */
851 headMB = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
852 if (headMB == NULL) {
853 PPPDEBUG(LOG_WARNING, ("pppifOutput[%d]: first alloc fail\n", pd));
854 LINK_STATS_INC(link.memerr);
855 LINK_STATS_INC(link.drop);
856 snmp_inc_ifoutdiscards(netif);
862 * Attempt Van Jacobson header compression if VJ is configured and
863 * this is an IP packet.
865 if (protocol == PPP_IP && pc->vjEnabled) {
866 switch (vj_compress_tcp(&pc->vjComp, pb)) {
869 protocol = PPP_IP_PROTOCOL; */
871 case TYPE_COMPRESSED_TCP:
872 protocol = PPP_VJC_COMP;
874 case TYPE_UNCOMPRESSED_TCP:
875 protocol = PPP_VJC_UNCOMP;
878 PPPDEBUG(LOG_WARNING, ("pppifOutput[%d]: bad IP packet\n", pd));
879 LINK_STATS_INC(link.proterr);
880 LINK_STATS_INC(link.drop);
881 snmp_inc_ifoutdiscards(netif);
886 #endif /* VJ_SUPPORT */
890 /* Build the PPP header. */
891 if ((sys_jiffies() - pc->lastXMit) >= PPP_MAXIDLEFLAG) {
892 tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
895 pc->lastXMit = sys_jiffies();
897 fcsOut = PPP_FCS(fcsOut, PPP_ALLSTATIONS);
898 tailMB = pppAppend(PPP_ALLSTATIONS, tailMB, &pc->outACCM);
899 fcsOut = PPP_FCS(fcsOut, PPP_UI);
900 tailMB = pppAppend(PPP_UI, tailMB, &pc->outACCM);
902 if (!pc->pcomp || protocol > 0xFF) {
903 c = (protocol >> 8) & 0xFF;
904 fcsOut = PPP_FCS(fcsOut, c);
905 tailMB = pppAppend(c, tailMB, &pc->outACCM);
908 fcsOut = PPP_FCS(fcsOut, c);
909 tailMB = pppAppend(c, tailMB, &pc->outACCM);
912 for(p = pb; p; p = p->next) {
916 sPtr = (u_char*)p->payload;
921 /* Update FCS before checking for special characters. */
922 fcsOut = PPP_FCS(fcsOut, c);
924 /* Copy to output buffer escaping special characters. */
925 tailMB = pppAppend(c, tailMB, &pc->outACCM);
929 /* Add FCS and trailing flag. */
931 tailMB = pppAppend(c, tailMB, &pc->outACCM);
932 c = (~fcsOut >> 8) & 0xFF;
933 tailMB = pppAppend(c, tailMB, &pc->outACCM);
934 tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
936 /* If we failed to complete the packet, throw it away. */
938 PPPDEBUG(LOG_WARNING,
939 ("pppifOutput[%d]: Alloc err - dropping proto=%d\n",
942 LINK_STATS_INC(link.memerr);
943 LINK_STATS_INC(link.drop);
944 snmp_inc_ifoutdiscards(netif);
949 PPPDEBUG(LOG_INFO, ("pppifOutput[%d]: proto=0x%"X16_F"\n", pd, protocol));
952 #endif /* PPPOS_SUPPORT */
957 /* Get and set parameters for the given connection.
958 * Return 0 on success, an error code on failure. */
960 pppIOCtl(int pd, int cmd, void *arg)
962 PPPControl *pc = &pppControl[pd];
965 if (pd < 0 || pd >= NUM_PPP) {
969 case PPPCTLG_UPSTATUS: /* Get the PPP up status. */
971 *(int *)arg = (int)(pc->if_up);
976 case PPPCTLS_ERRCODE: /* Set the PPP error code. */
978 pc->errCode = *(int *)arg;
983 case PPPCTLG_ERRCODE: /* Get the PPP error code. */
985 *(int *)arg = (int)(pc->errCode);
991 case PPPCTLG_FD: /* Get the fd associated with the ppp */
993 *(sio_fd_t *)arg = pc->fd;
998 #endif /* PPPOS_SUPPORT */
1009 * Return the Maximum Transmission Unit for the given PPP connection.
1014 PPPControl *pc = &pppControl[pd];
1017 /* Validate parameters. */
1018 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
1029 pppWriteOverEthernet(int pd, const u_char *s, int n)
1031 PPPControl *pc = &pppControl[pd];
1034 /* skip address & flags */
1038 LWIP_ASSERT("PPPOE_HDRLEN + n <= 0xffff", PPPOE_HDRLEN + n <= 0xffff);
1039 pb = pbuf_alloc(PBUF_LINK, (u16_t)(PPPOE_HDRLEN + n), PBUF_RAM);
1041 LINK_STATS_INC(link.memerr);
1042 LINK_STATS_INC(link.proterr);
1043 snmp_inc_ifoutdiscards(&pc->netif);
1044 return PPPERR_ALLOC;
1047 pbuf_header(pb, -(s16_t)PPPOE_HDRLEN);
1049 pc->lastXMit = sys_jiffies();
1051 MEMCPY(pb->payload, s, n);
1053 if(pppoe_xmit(pc->pppoe_sc, pb) != ERR_OK) {
1054 LINK_STATS_INC(link.err);
1055 snmp_inc_ifoutdiscards(&pc->netif);
1056 return PPPERR_DEVICE;
1059 snmp_add_ifoutoctets(&pc->netif, (u16_t)n);
1060 snmp_inc_ifoutucastpkts(&pc->netif);
1061 LINK_STATS_INC(link.xmit);
1064 #endif /* PPPOE_SUPPORT */
1067 * Write n characters to a ppp link.
1068 * RETURN: >= 0 Number of characters written
1069 * -1 Failed to write to device
1072 pppWrite(int pd, const u_char *s, int n)
1074 PPPControl *pc = &pppControl[pd];
1078 struct pbuf *headMB, *tailMB;
1079 #endif /* PPPOS_SUPPORT */
1083 return pppWriteOverEthernet(pd, s, n);
1085 #endif /* PPPOE_SUPPORT */
1088 headMB = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
1089 if (headMB == NULL) {
1090 LINK_STATS_INC(link.memerr);
1091 LINK_STATS_INC(link.proterr);
1092 snmp_inc_ifoutdiscards(&pc->netif);
1093 return PPPERR_ALLOC;
1098 /* If the link has been idle, we'll send a fresh flag character to
1099 * flush any noise. */
1100 if ((sys_jiffies() - pc->lastXMit) >= PPP_MAXIDLEFLAG) {
1101 tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
1103 pc->lastXMit = sys_jiffies();
1105 fcsOut = PPP_INITFCS;
1106 /* Load output buffer. */
1110 /* Update FCS before checking for special characters. */
1111 fcsOut = PPP_FCS(fcsOut, c);
1113 /* Copy to output buffer escaping special characters. */
1114 tailMB = pppAppend(c, tailMB, &pc->outACCM);
1117 /* Add FCS and trailing flag. */
1119 tailMB = pppAppend(c, tailMB, &pc->outACCM);
1120 c = (~fcsOut >> 8) & 0xFF;
1121 tailMB = pppAppend(c, tailMB, &pc->outACCM);
1122 tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
1124 /* If we failed to complete the packet, throw it away.
1125 * Otherwise send it. */
1127 PPPDEBUG(LOG_WARNING,
1128 ("pppWrite[%d]: Alloc err - dropping pbuf len=%d\n", pd, headMB->len));
1129 /*"pppWrite[%d]: Alloc err - dropping %d:%.*H", pd, headMB->len, LWIP_MIN(headMB->len * 2, 40), headMB->payload)); */
1131 LINK_STATS_INC(link.memerr);
1132 LINK_STATS_INC(link.proterr);
1133 snmp_inc_ifoutdiscards(&pc->netif);
1134 return PPPERR_ALLOC;
1137 PPPDEBUG(LOG_INFO, ("pppWrite[%d]: len=%d\n", pd, headMB->len));
1138 /* "pppWrite[%d]: %d:%.*H", pd, headMB->len, LWIP_MIN(headMB->len * 2, 40), headMB->payload)); */
1140 #endif /* PPPOS_SUPPORT */
1146 * ppp_send_config - configure the transmit characteristics of
1147 * the ppp interface.
1150 ppp_send_config( int unit, u16_t mtu, u32_t asyncmap, int pcomp, int accomp)
1152 PPPControl *pc = &pppControl[unit];
1157 pc->accomp = accomp;
1159 /* Load the ACCM bits for the 32 control codes. */
1160 for (i = 0; i < 32/8; i++) {
1161 pc->outACCM[i] = (u_char)((asyncmap >> (8 * i)) & 0xFF);
1163 PPPDEBUG(LOG_INFO, ("ppp_send_config[%d]: outACCM=%X %X %X %X\n",
1165 pc->outACCM[0], pc->outACCM[1], pc->outACCM[2], pc->outACCM[3]));
1170 * ppp_set_xaccm - set the extended transmit ACCM for the interface.
1173 ppp_set_xaccm(int unit, ext_accm *accm)
1175 SMEMCPY(pppControl[unit].outACCM, accm, sizeof(ext_accm));
1176 PPPDEBUG(LOG_INFO, ("ppp_set_xaccm[%d]: outACCM=%X %X %X %X\n",
1178 pppControl[unit].outACCM[0],
1179 pppControl[unit].outACCM[1],
1180 pppControl[unit].outACCM[2],
1181 pppControl[unit].outACCM[3]));
1186 * ppp_recv_config - configure the receive-side characteristics of
1187 * the ppp interface.
1190 ppp_recv_config( int unit, int mru, u32_t asyncmap, int pcomp, int accomp)
1192 PPPControl *pc = &pppControl[unit];
1194 SYS_ARCH_DECL_PROTECT(lev);
1196 LWIP_UNUSED_ARG(accomp);
1197 LWIP_UNUSED_ARG(pcomp);
1198 LWIP_UNUSED_ARG(mru);
1200 /* Load the ACCM bits for the 32 control codes. */
1201 SYS_ARCH_PROTECT(lev);
1202 for (i = 0; i < 32 / 8; i++) {
1203 /* @todo: does this work? ext_accm has been modified from pppd! */
1204 pc->rx.inACCM[i] = (u_char)(asyncmap >> (i * 8));
1206 SYS_ARCH_UNPROTECT(lev);
1207 PPPDEBUG(LOG_INFO, ("ppp_recv_config[%d]: inACCM=%X %X %X %X\n",
1209 pc->rx.inACCM[0], pc->rx.inACCM[1], pc->rx.inACCM[2], pc->rx.inACCM[3]));
1214 * ccp_test - ask kernel whether a given compression method
1215 * is acceptable for use. Returns 1 if the method and parameters
1216 * are OK, 0 if the method is known but the parameters are not OK
1217 * (e.g. code size should be reduced), or -1 if the method is unknown.
1220 ccp_test( int unit, int opt_len, int for_transmit, u_char *opt_ptr)
1222 return 0; /* XXX Currently no compression. */
1226 * ccp_flags_set - inform kernel about the current state of CCP.
1229 ccp_flags_set(int unit, int isopen, int isup)
1235 * ccp_fatal_error - returns 1 if decompression was disabled as a
1236 * result of an error detected after decompression of a packet,
1237 * 0 otherwise. This is necessary because of patent nonsense.
1240 ccp_fatal_error(int unit)
1248 * get_idle_time - return how long the link has been idle.
1251 get_idle_time(int u, struct ppp_idle *ip)
1255 LWIP_UNUSED_ARG(ip);
1262 * Return user specified netmask, modified by any mask we might determine
1263 * for address `addr' (in network byte order).
1264 * Here we scan through the system's list of interfaces, looking for
1265 * any non-point-to-point interfaces which might appear to be on the same
1266 * network as `addr'. If we find any, we OR in their netmask to the
1267 * user-specified netmask.
1275 if (IP_CLASSA(addr)) { /* determine network mask for address class */
1276 nmask = IP_CLASSA_NET;
1277 } else if (IP_CLASSB(addr)) {
1278 nmask = IP_CLASSB_NET;
1280 nmask = IP_CLASSC_NET;
1283 /* class D nets are disallowed by bad_ip_adrs */
1284 mask = subnetMask | htonl(nmask);
1287 * Scan through the system's network interfaces.
1288 * Get each netmask and OR them into our mask.
1295 * sifvjcomp - config tcp header compression
1298 sifvjcomp(int pd, int vjcomp, u8_t cidcomp, u8_t maxcid)
1300 #if PPPOS_SUPPORT && VJ_SUPPORT
1301 PPPControl *pc = &pppControl[pd];
1303 pc->vjEnabled = vjcomp;
1304 pc->vjComp.compressSlot = cidcomp;
1305 pc->vjComp.maxSlotIndex = maxcid;
1306 PPPDEBUG(LOG_INFO, ("sifvjcomp: VJ compress enable=%d slot=%d max slot=%d\n",
1307 vjcomp, cidcomp, maxcid));
1308 #else /* PPPOS_SUPPORT && VJ_SUPPORT */
1309 LWIP_UNUSED_ARG(pd);
1310 LWIP_UNUSED_ARG(vjcomp);
1311 LWIP_UNUSED_ARG(cidcomp);
1312 LWIP_UNUSED_ARG(maxcid);
1313 #endif /* PPPOS_SUPPORT && VJ_SUPPORT */
1319 * pppifNetifInit - netif init callback
1322 pppifNetifInit(struct netif *netif)
1324 netif->name[0] = 'p';
1325 netif->name[1] = 'p';
1326 netif->output = pppifOutput;
1327 netif->mtu = pppMTU((int)(size_t)netif->state);
1328 netif->flags = NETIF_FLAG_POINTTOPOINT | NETIF_FLAG_LINK_UP;
1329 #if LWIP_NETIF_HOSTNAME
1330 /* @todo: Initialize interface hostname */
1331 /* netif_set_hostname(netif, "lwip"); */
1332 #endif /* LWIP_NETIF_HOSTNAME */
1338 * sifup - Config the interface up and enable IP packets to pass.
1343 PPPControl *pc = &pppControl[pd];
1346 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
1348 PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd));
1350 netif_remove(&pc->netif);
1351 if (netif_add(&pc->netif, &pc->addrs.our_ipaddr, &pc->addrs.netmask,
1352 &pc->addrs.his_ipaddr, (void *)(size_t)pd, pppifNetifInit, ip_input)) {
1353 netif_set_up(&pc->netif);
1355 pc->errCode = PPPERR_NONE;
1357 PPPDEBUG(LOG_DEBUG, ("sifup: unit %d: linkStatusCB=%p errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));
1358 if (pc->linkStatusCB) {
1359 pc->linkStatusCB(pc->linkStatusCtx, pc->errCode, &pc->addrs);
1363 PPPDEBUG(LOG_ERR, ("sifup[%d]: netif_add failed\n", pd));
1371 * sifnpmode - Set the mode for handling packets for a given NP.
1374 sifnpmode(int u, int proto, enum NPmode mode)
1377 LWIP_UNUSED_ARG(proto);
1378 LWIP_UNUSED_ARG(mode);
1383 * sifdown - Config the interface down and disable IP.
1388 PPPControl *pc = &pppControl[pd];
1391 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
1393 PPPDEBUG(LOG_WARNING, ("sifdown[%d]: bad parms\n", pd));
1396 /* make sure the netif status callback is called */
1397 netif_set_down(&pc->netif);
1398 netif_remove(&pc->netif);
1399 PPPDEBUG(LOG_DEBUG, ("sifdown: unit %d: linkStatusCB=%p errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));
1400 if (pc->linkStatusCB) {
1401 pc->linkStatusCB(pc->linkStatusCtx, PPPERR_CONNECT, NULL);
1408 * sifaddr - Config the interface IP addresses and netmask.
1409 * @param pd Interface unit ???
1410 * @param o Our IP address ???
1411 * @param h His IP address ???
1412 * @param m IP subnet mask ???
1413 * @param ns1 Primary DNS
1414 * @param ns2 Secondary DNS
1417 sifaddr( int pd, u32_t o, u32_t h, u32_t m, u32_t ns1, u32_t ns2)
1419 PPPControl *pc = &pppControl[pd];
1422 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
1424 PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd));
1426 SMEMCPY(&pc->addrs.our_ipaddr, &o, sizeof(o));
1427 SMEMCPY(&pc->addrs.his_ipaddr, &h, sizeof(h));
1428 SMEMCPY(&pc->addrs.netmask, &m, sizeof(m));
1429 SMEMCPY(&pc->addrs.dns1, &ns1, sizeof(ns1));
1430 SMEMCPY(&pc->addrs.dns2, &ns2, sizeof(ns2));
1436 * cifaddr - Clear the interface IP addresses, and delete routes
1437 * through the interface if possible.
1438 * @param pd Interface unit ???
1439 * @param o Our IP address ???
1440 * @param h IP broadcast address ???
1443 cifaddr( int pd, u32_t o, u32_t h)
1445 PPPControl *pc = &pppControl[pd];
1450 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
1452 PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd));
1454 IP4_ADDR(&pc->addrs.our_ipaddr, 0,0,0,0);
1455 IP4_ADDR(&pc->addrs.his_ipaddr, 0,0,0,0);
1456 IP4_ADDR(&pc->addrs.netmask, 255,255,255,0);
1457 IP4_ADDR(&pc->addrs.dns1, 0,0,0,0);
1458 IP4_ADDR(&pc->addrs.dns2, 0,0,0,0);
1464 * sifdefaultroute - assign a default route through the address given.
1467 sifdefaultroute(int pd, u32_t l, u32_t g)
1469 PPPControl *pc = &pppControl[pd];
1475 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
1477 PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd));
1479 netif_set_default(&pc->netif);
1482 /* TODO: check how PPP handled the netMask, previously not set by ipSetDefault */
1488 * cifdefaultroute - delete a default route through the address given.
1491 cifdefaultroute(int pd, u32_t l, u32_t g)
1493 PPPControl *pc = &pppControl[pd];
1499 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
1501 PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd));
1503 netif_set_default(NULL);
1509 /**********************************/
1510 /*** LOCAL FUNCTION DEFINITIONS ***/
1511 /**********************************/
1513 #if PPPOS_SUPPORT && PPP_INPROC_OWNTHREAD
1514 /* The main PPP process function. This implements the state machine according
1515 * to section 4 of RFC 1661: The Point-To-Point Protocol. */
1517 pppInputThread(void *arg)
1520 PPPControlRx *pcrx = arg;
1522 while (lcp_phase[pcrx->pd] != PHASE_DEAD) {
1523 count = sio_read(pcrx->fd, pcrx->rxbuf, PPPOS_RX_BUFSIZE);
1525 pppInProc(pcrx, pcrx->rxbuf, count);
1527 /* nothing received, give other tasks a chance to run */
1532 #endif /* PPPOS_SUPPORT && PPP_INPROC_OWNTHREAD */
1537 pppOverEthernetInitFailed(int pd)
1544 pc = &pppControl[pd];
1545 pppoe_destroy(&pc->netif);
1548 if(pc->linkStatusCB) {
1549 pc->linkStatusCB(pc->linkStatusCtx, pc->errCode ? pc->errCode : PPPERR_PROTOCOL, NULL);
1554 pppOverEthernetLinkStatusCB(int pd, int up)
1557 PPPDEBUG(LOG_INFO, ("pppOverEthernetLinkStatusCB: unit %d: Connecting\n", pd));
1560 pppOverEthernetInitFailed(pd);
1563 #endif /* PPPOE_SUPPORT */
1566 pppSingleBuf(struct pbuf *p)
1571 if(p->tot_len == p->len) {
1575 q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
1578 ("pppSingleBuf: unable to alloc new buf (%d)\n", p->tot_len));
1579 return p; /* live dangerously */
1582 for(b = p, pl = q->payload; b != NULL; b = b->next) {
1583 MEMCPY(pl, b->payload, b->len);
1592 struct pppInputHeader {
1598 * Pass the processed input packet to the appropriate handler.
1599 * This function and all handlers run in the context of the tcpip_thread
1604 struct pbuf *nb = (struct pbuf *)arg;
1608 pd = ((struct pppInputHeader *)nb->payload)->unit;
1609 protocol = ((struct pppInputHeader *)nb->payload)->proto;
1611 if(pbuf_header(nb, -(int)sizeof(struct pppInputHeader))) {
1612 LWIP_ASSERT("pbuf_header failed\n", 0);
1616 LINK_STATS_INC(link.recv);
1617 snmp_inc_ifinucastpkts(&pppControl[pd].netif);
1618 snmp_add_ifinoctets(&pppControl[pd].netif, nb->tot_len);
1621 * Toss all non-LCP packets unless LCP is OPEN.
1622 * Until we get past the authentication phase, toss all packets
1623 * except LCP, LQR and authentication packets.
1625 if((lcp_phase[pd] <= PHASE_AUTHENTICATE) && (protocol != PPP_LCP)) {
1626 if(!((protocol == PPP_LQR) || (protocol == PPP_PAP) || (protocol == PPP_CHAP)) ||
1627 (lcp_phase[pd] != PHASE_AUTHENTICATE)) {
1628 PPPDEBUG(LOG_INFO, ("pppInput: discarding proto 0x%"X16_F" in phase %d\n", protocol, lcp_phase[pd]));
1634 case PPP_VJC_COMP: /* VJ compressed TCP */
1635 #if PPPOS_SUPPORT && VJ_SUPPORT
1636 PPPDEBUG(LOG_INFO, ("pppInput[%d]: vj_comp in pbuf len=%d\n", pd, nb->len));
1638 * Clip off the VJ header and prepend the rebuilt TCP/IP header and
1639 * pass the result to IP.
1641 if ((vj_uncompress_tcp(&nb, &pppControl[pd].vjComp) >= 0) && (pppControl[pd].netif.input)) {
1642 pppControl[pd].netif.input(nb, &pppControl[pd].netif);
1645 /* Something's wrong so drop it. */
1646 PPPDEBUG(LOG_WARNING, ("pppInput[%d]: Dropping VJ compressed\n", pd));
1647 #else /* PPPOS_SUPPORT && VJ_SUPPORT */
1648 /* No handler for this protocol so drop the packet. */
1649 PPPDEBUG(LOG_INFO, ("pppInput[%d]: drop VJ Comp in %d:%s\n", pd, nb->len, nb->payload));
1650 #endif /* PPPOS_SUPPORT && VJ_SUPPORT */
1653 case PPP_VJC_UNCOMP: /* VJ uncompressed TCP */
1654 #if PPPOS_SUPPORT && VJ_SUPPORT
1655 PPPDEBUG(LOG_INFO, ("pppInput[%d]: vj_un in pbuf len=%d\n", pd, nb->len));
1657 * Process the TCP/IP header for VJ header compression and then pass
1660 if ((vj_uncompress_uncomp(nb, &pppControl[pd].vjComp) >= 0) && pppControl[pd].netif.input) {
1661 pppControl[pd].netif.input(nb, &pppControl[pd].netif);
1664 /* Something's wrong so drop it. */
1665 PPPDEBUG(LOG_WARNING, ("pppInput[%d]: Dropping VJ uncompressed\n", pd));
1666 #else /* PPPOS_SUPPORT && VJ_SUPPORT */
1667 /* No handler for this protocol so drop the packet. */
1669 ("pppInput[%d]: drop VJ UnComp in %d:.*H\n",
1670 pd, nb->len, LWIP_MIN(nb->len * 2, 40), nb->payload));
1671 #endif /* PPPOS_SUPPORT && VJ_SUPPORT */
1674 case PPP_IP: /* Internet Protocol */
1675 PPPDEBUG(LOG_INFO, ("pppInput[%d]: ip in pbuf len=%d\n", pd, nb->len));
1676 if (pppControl[pd].netif.input) {
1677 pppControl[pd].netif.input(nb, &pppControl[pd].netif);
1683 struct protent *protp;
1687 * Upcall the proper protocol input routine.
1689 for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) {
1690 if (protp->protocol == protocol && protp->enabled_flag) {
1691 PPPDEBUG(LOG_INFO, ("pppInput[%d]: %s len=%d\n", pd, protp->name, nb->len));
1692 nb = pppSingleBuf(nb);
1693 (*protp->input)(pd, nb->payload, nb->len);
1694 PPPDEBUG(LOG_DETAIL, ("pppInput[%d]: packet processed\n", pd));
1699 /* No handler for this protocol so reject the packet. */
1700 PPPDEBUG(LOG_INFO, ("pppInput[%d]: rejecting unsupported proto 0x%"X16_F" len=%d\n", pd, protocol, nb->len));
1701 if (pbuf_header(nb, sizeof(protocol))) {
1702 LWIP_ASSERT("pbuf_header failed\n", 0);
1705 #if BYTE_ORDER == LITTLE_ENDIAN
1706 protocol = htons(protocol);
1707 SMEMCPY(nb->payload, &protocol, sizeof(protocol));
1708 #endif /* BYTE_ORDER == LITTLE_ENDIAN */
1709 lcp_sprotrej(pd, nb->payload, nb->len);
1715 LINK_STATS_INC(link.drop);
1716 snmp_inc_ifindiscards(&pppControl[pd].netif);
1725 * Drop the input packet.
1728 pppDrop(PPPControlRx *pcrx)
1730 if (pcrx->inHead != NULL) {
1732 PPPDEBUG(LOG_INFO, ("pppDrop: %d:%.*H\n", pcrx->inHead->len, min(60, pcrx->inHead->len * 2), pcrx->inHead->payload));
1734 PPPDEBUG(LOG_INFO, ("pppDrop: pbuf len=%d, addr %p\n", pcrx->inHead->len, (void*)pcrx->inHead));
1735 if (pcrx->inTail && (pcrx->inTail != pcrx->inHead)) {
1736 pbuf_free(pcrx->inTail);
1738 pbuf_free(pcrx->inHead);
1739 pcrx->inHead = NULL;
1740 pcrx->inTail = NULL;
1743 vj_uncompress_err(&pppControl[pcrx->pd].vjComp);
1744 #endif /* VJ_SUPPORT */
1746 LINK_STATS_INC(link.drop);
1747 snmp_inc_ifindiscards(&pppControl[pcrx->pd].netif);
1750 /** Pass received raw characters to PPPoS to be decoded. This function is
1751 * thread-safe and can be called from a dedicated RX-thread or from a main-loop.
1753 * @param pd PPP descriptor index, returned by pppOpen()
1754 * @param data received data
1755 * @param len length of received data
1758 pppos_input(int pd, u_char* data, int len)
1760 pppInProc(&pppControl[pd].rx, data, len);
1764 * Process a received octet string.
1767 pppInProc(PPPControlRx *pcrx, u_char *s, int l)
1769 struct pbuf *nextNBuf;
1772 SYS_ARCH_DECL_PROTECT(lev);
1774 PPPDEBUG(LOG_DEBUG, ("pppInProc[%d]: got %d bytes\n", pcrx->pd, l));
1778 SYS_ARCH_PROTECT(lev);
1779 escaped = ESCAPE_P(pcrx->inACCM, curChar);
1780 SYS_ARCH_UNPROTECT(lev);
1781 /* Handle special characters. */
1783 /* Check for escape sequences. */
1784 /* XXX Note that this does not handle an escaped 0x5d character which
1785 * would appear as an escape character. Since this is an ASCII ']'
1786 * and there is no reason that I know of to escape it, I won't complicate
1787 * the code to handle this case. GLL */
1788 if (curChar == PPP_ESCAPE) {
1789 pcrx->inEscaped = 1;
1790 /* Check for the flag character. */
1791 } else if (curChar == PPP_FLAG) {
1792 /* If this is just an extra flag character, ignore it. */
1793 if (pcrx->inState <= PDADDRESS) {
1795 /* If we haven't received the packet header, drop what has come in. */
1796 } else if (pcrx->inState < PDDATA) {
1797 PPPDEBUG(LOG_WARNING,
1798 ("pppInProc[%d]: Dropping incomplete packet %d\n",
1799 pcrx->pd, pcrx->inState));
1800 LINK_STATS_INC(link.lenerr);
1802 /* If the fcs is invalid, drop the packet. */
1803 } else if (pcrx->inFCS != PPP_GOODFCS) {
1805 ("pppInProc[%d]: Dropping bad fcs 0x%"X16_F" proto=0x%"X16_F"\n",
1806 pcrx->pd, pcrx->inFCS, pcrx->inProtocol));
1807 /* Note: If you get lots of these, check for UART frame errors or try different baud rate */
1808 LINK_STATS_INC(link.chkerr);
1810 /* Otherwise it's a good packet so pass it on. */
1812 /* Trim off the checksum. */
1813 if(pcrx->inTail->len >= 2) {
1814 pcrx->inTail->len -= 2;
1816 pcrx->inTail->tot_len = pcrx->inTail->len;
1817 if (pcrx->inTail != pcrx->inHead) {
1818 pbuf_cat(pcrx->inHead, pcrx->inTail);
1821 pcrx->inTail->tot_len = pcrx->inTail->len;
1822 if (pcrx->inTail != pcrx->inHead) {
1823 pbuf_cat(pcrx->inHead, pcrx->inTail);
1826 pbuf_realloc(pcrx->inHead, pcrx->inHead->tot_len - 2);
1829 /* Dispatch the packet thereby consuming it. */
1830 #if PPP_INPROC_MULTITHREADED
1831 if(tcpip_callback_with_block(pppInput, pcrx->inHead, 0) != ERR_OK) {
1832 PPPDEBUG(LOG_ERR, ("pppInProc[%d]: tcpip_callback() failed, dropping packet\n", pcrx->pd));
1833 pbuf_free(pcrx->inHead);
1834 LINK_STATS_INC(link.drop);
1835 snmp_inc_ifindiscards(&pppControl[pcrx->pd].netif);
1837 #else /* PPP_INPROC_MULTITHREADED */
1838 pppInput(pcrx->inHead);
1839 #endif /* PPP_INPROC_MULTITHREADED */
1840 pcrx->inHead = NULL;
1841 pcrx->inTail = NULL;
1844 /* Prepare for a new packet. */
1845 pcrx->inFCS = PPP_INITFCS;
1846 pcrx->inState = PDADDRESS;
1847 pcrx->inEscaped = 0;
1848 /* Other characters are usually control characters that may have
1849 * been inserted by the physical layer so here we just drop them. */
1851 PPPDEBUG(LOG_WARNING,
1852 ("pppInProc[%d]: Dropping ACCM char <%d>\n", pcrx->pd, curChar));
1854 /* Process other characters. */
1856 /* Unencode escaped characters. */
1857 if (pcrx->inEscaped) {
1858 pcrx->inEscaped = 0;
1859 curChar ^= PPP_TRANS;
1862 /* Process character relative to current state. */
1863 switch(pcrx->inState) {
1864 case PDIDLE: /* Idle state - waiting. */
1865 /* Drop the character if it's not 0xff
1866 * we would have processed a flag character above. */
1867 if (curChar != PPP_ALLSTATIONS) {
1872 case PDSTART: /* Process start flag. */
1873 /* Prepare for a new packet. */
1874 pcrx->inFCS = PPP_INITFCS;
1877 case PDADDRESS: /* Process address field. */
1878 if (curChar == PPP_ALLSTATIONS) {
1879 pcrx->inState = PDCONTROL;
1882 /* Else assume compressed address and control fields so
1883 * fall through to get the protocol... */
1884 case PDCONTROL: /* Process control field. */
1885 /* If we don't get a valid control code, restart. */
1886 if (curChar == PPP_UI) {
1887 pcrx->inState = PDPROTOCOL1;
1892 PPPDEBUG(LOG_WARNING,
1893 ("pppInProc[%d]: Invalid control <%d>\n", pcrx->pd, curChar));
1894 pcrx->inState = PDSTART;
1897 case PDPROTOCOL1: /* Process protocol field 1. */
1898 /* If the lower bit is set, this is the end of the protocol
1901 pcrx->inProtocol = curChar;
1902 pcrx->inState = PDDATA;
1904 pcrx->inProtocol = (u_int)curChar << 8;
1905 pcrx->inState = PDPROTOCOL2;
1908 case PDPROTOCOL2: /* Process protocol field 2. */
1909 pcrx->inProtocol |= curChar;
1910 pcrx->inState = PDDATA;
1912 case PDDATA: /* Process data byte. */
1913 /* Make space to receive processed data. */
1914 if (pcrx->inTail == NULL || pcrx->inTail->len == PBUF_POOL_BUFSIZE) {
1916 pcrx->inTail->tot_len = pcrx->inTail->len;
1917 if (pcrx->inTail != pcrx->inHead) {
1918 pbuf_cat(pcrx->inHead, pcrx->inTail);
1921 /* If we haven't started a packet, we need a packet header. */
1922 nextNBuf = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
1923 if (nextNBuf == NULL) {
1924 /* No free buffers. Drop the input packet and let the
1925 * higher layers deal with it. Continue processing
1926 * the received pbuf chain in case a new packet starts. */
1927 PPPDEBUG(LOG_ERR, ("pppInProc[%d]: NO FREE MBUFS!\n", pcrx->pd));
1928 LINK_STATS_INC(link.memerr);
1930 pcrx->inState = PDSTART; /* Wait for flag sequence. */
1933 if (pcrx->inHead == NULL) {
1934 struct pppInputHeader *pih = nextNBuf->payload;
1936 pih->unit = pcrx->pd;
1937 pih->proto = pcrx->inProtocol;
1939 nextNBuf->len += sizeof(*pih);
1941 pcrx->inHead = nextNBuf;
1943 pcrx->inTail = nextNBuf;
1945 /* Load character into buffer. */
1946 ((u_char*)pcrx->inTail->payload)[pcrx->inTail->len++] = curChar;
1950 /* update the frame check sequence number. */
1951 pcrx->inFCS = PPP_FCS(pcrx->inFCS, curChar);
1953 } /* while (l-- > 0), all bytes processed */
1957 #endif /* PPPOS_SUPPORT */
1961 pppInProcOverEthernet(int pd, struct pbuf *pb)
1963 struct pppInputHeader *pih;
1966 if(pb->len < sizeof(inProtocol)) {
1967 PPPDEBUG(LOG_ERR, ("pppInProcOverEthernet: too small for protocol field\n"));
1971 inProtocol = (((u8_t *)pb->payload)[0] << 8) | ((u8_t*)pb->payload)[1];
1973 /* make room for pppInputHeader - should not fail */
1974 if (pbuf_header(pb, sizeof(*pih) - sizeof(inProtocol)) != 0) {
1975 PPPDEBUG(LOG_ERR, ("pppInProcOverEthernet: could not allocate room for header\n"));
1982 pih->proto = inProtocol;
1984 /* Dispatch the packet thereby consuming it. */
1989 LINK_STATS_INC(link.drop);
1990 snmp_inc_ifindiscards(&pppControl[pd].netif);
1994 #endif /* PPPOE_SUPPORT */
1996 #if LWIP_NETIF_STATUS_CALLBACK
1997 /** Set the status callback of a PPP's netif
1999 * @param pd The PPP descriptor returned by pppOpen()
2000 * @param status_callback pointer to the status callback function
2002 * @see netif_set_status_callback
2005 ppp_set_netif_statuscallback(int pd, netif_status_callback_fn status_callback)
2007 netif_set_status_callback(&pppControl[pd].netif, status_callback);
2009 #endif /* LWIP_NETIF_STATUS_CALLBACK */
2011 #if LWIP_NETIF_LINK_CALLBACK
2012 /** Set the link callback of a PPP's netif
2014 * @param pd The PPP descriptor returned by pppOpen()
2015 * @param link_callback pointer to the link callback function
2017 * @see netif_set_link_callback
2020 ppp_set_netif_linkcallback(int pd, netif_status_callback_fn link_callback)
2022 netif_set_link_callback(&pppControl[pd].netif, link_callback);
2024 #endif /* LWIP_NETIF_LINK_CALLBACK */
2026 #endif /* PPP_SUPPORT */