Home | History | Annotate | Download | only in ppp
      1 /*****************************************************************************
      2 * ppp.c - Network Point to Point Protocol program file.
      3 *
      4 * Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
      5 * portions Copyright (c) 1997 by Global Election Systems Inc.
      6 *
      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.
     13 *
     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.
     24 *
     25 ******************************************************************************
     26 * REVISION HISTORY
     27 *
     28 * 03-01-01 Marc Boucher <marc (at) mbsi.ca>
     29 *   Ported to lwIP.
     30 * 97-11-05 Guy Lancaster <lancasterg (at) acm.org>, Global Election Systems Inc.
     31 *   Original.
     32 *****************************************************************************/
     33 
     34 /*
     35  * ppp_defs.h - PPP definitions.
     36  *
     37  * if_pppvar.h - private structures and declarations for PPP.
     38  *
     39  * Copyright (c) 1994 The Australian National University.
     40  * All rights reserved.
     41  *
     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
     47  * any purpose.
     48  *
     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
     53  * OF SUCH DAMAGE.
     54  *
     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,
     60  * OR MODIFICATIONS.
     61  */
     62 
     63 /*
     64  * if_ppp.h - Point-to-Point Protocol definitions.
     65  *
     66  * Copyright (c) 1989 Carnegie Mellon University.
     67  * All rights reserved.
     68  *
     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.
     80  */
     81 
     82 #include "lwip/opt.h"
     83 
     84 #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
     85 
     86 #include "lwip/ip.h" /* for ip_input() */
     87 
     88 #include "ppp.h"
     89 #include "pppdebug.h"
     90 
     91 #include "randm.h"
     92 #include "fsm.h"
     93 #if PAP_SUPPORT
     94 #include "pap.h"
     95 #endif /* PAP_SUPPORT */
     96 #if CHAP_SUPPORT
     97 #include "chap.h"
     98 #endif /* CHAP_SUPPORT */
     99 #include "ipcp.h"
    100 #include "lcp.h"
    101 #include "magic.h"
    102 #include "auth.h"
    103 #if VJ_SUPPORT
    104 #include "vj.h"
    105 #endif /* VJ_SUPPORT */
    106 #if PPPOE_SUPPORT
    107 #include "netif/ppp_oe.h"
    108 #endif /* PPPOE_SUPPORT */
    109 
    110 #include "lwip/tcpip.h"
    111 #include "lwip/api.h"
    112 #include "lwip/snmp.h"
    113 
    114 #include <string.h>
    115 
    116 /*************************/
    117 /*** LOCAL DEFINITIONS ***/
    118 /*************************/
    119 
    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).
    123  */
    124 #ifndef PPP_INPROC_MULTITHREADED
    125 #define PPP_INPROC_MULTITHREADED (NO_SYS==0)
    126 #endif
    127 
    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
    133 #endif
    134 
    135 #if PPP_INPROC_OWNTHREAD && !PPP_INPROC_MULTITHREADED
    136   #error "PPP_INPROC_OWNTHREAD needs PPP_INPROC_MULTITHREADED==1"
    137 #endif
    138 
    139 /*
    140  * The basic PPP frame.
    141  */
    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])
    145 
    146 /* PPP packet parser states.  Current state indicates operation yet to be
    147  * completed. */
    148 typedef enum {
    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. */
    156 } PPPDevStates;
    157 
    158 #define ESCAPE_P(accm, c) ((accm)[(c) >> 3] & pppACCMMask[c & 0x07])
    159 
    160 /************************/
    161 /*** LOCAL DATA TYPES ***/
    162 /************************/
    163 
    164 /** RX buffer size: this may be configured smaller! */
    165 #ifndef PPPOS_RX_BUFSIZE
    166 #define PPPOS_RX_BUFSIZE    (PPP_MRU + PPP_HDRLEN)
    167 #endif
    168 
    169 typedef struct PPPControlRx_s {
    170   /** unit number / ppp descriptor */
    171   int pd;
    172   /** the rx file descriptor */
    173   sio_fd_t fd;
    174   /** receive buffer - encoded data is stored here */
    175   u_char rxbuf[PPPOS_RX_BUFSIZE];
    176 
    177   /* The input packet. */
    178   struct pbuf *inHead, *inTail;
    179 
    180 #if PPPOS_SUPPORT
    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. */
    187 } PPPControlRx;
    188 
    189 /*
    190  * PPP interface control block.
    191  */
    192 typedef struct PPPControl_s {
    193   PPPControlRx rx;
    194   char openFlag;                /* True when in use. */
    195 #if PPPOE_SUPPORT
    196   struct netif *ethif;
    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. */
    201 #if PPPOS_SUPPORT
    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 */
    213 
    214   struct netif netif;
    215 
    216   struct ppp_addrs addrs;
    217 
    218   void (*linkStatusCB)(void *ctx, int errCode, void *arg);
    219   void *linkStatusCtx;
    220 
    221 } PPPControl;
    222 
    223 
    224 /*
    225  * Ioctl definitions.
    226  */
    227 
    228 struct npioctl {
    229   int         protocol; /* PPP procotol, e.g. PPP_IP */
    230   enum NPmode mode;
    231 };
    232 
    233 
    234 
    235 /***********************************/
    236 /*** LOCAL FUNCTION DECLARATIONS ***/
    237 /***********************************/
    238 #if PPPOS_SUPPORT
    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 */
    245 
    246 
    247 /******************************/
    248 /*** PUBLIC DATA STRUCTURES ***/
    249 /******************************/
    250 u_long subnetMask;
    251 
    252 static PPPControl pppControl[NUM_PPP]; /* The PPP interface control blocks. */
    253 
    254 /*
    255  * PPP Data Link Layer "protocol" table.
    256  * One entry per supported protocol.
    257  * The last entry must be NULL.
    258  */
    259 struct protent *ppp_protocols[] = {
    260   &lcp_protent,
    261 #if PAP_SUPPORT
    262   &pap_protent,
    263 #endif /* PAP_SUPPORT */
    264 #if CHAP_SUPPORT
    265   &chap_protent,
    266 #endif /* CHAP_SUPPORT */
    267 #if CBCP_SUPPORT
    268   &cbcp_protent,
    269 #endif /* CBCP_SUPPORT */
    270   &ipcp_protent,
    271 #if CCP_SUPPORT
    272   &ccp_protent,
    273 #endif /* CCP_SUPPORT */
    274   NULL
    275 };
    276 
    277 
    278 /*
    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.
    281  */
    282 u_char outpacket_buf[NUM_PPP][PPP_MRU+PPP_HDRLEN];
    283 
    284 
    285 /*****************************/
    286 /*** LOCAL DATA STRUCTURES ***/
    287 /*****************************/
    288 
    289 #if PPPOS_SUPPORT
    290 /*
    291  * FCS lookup table as calculated by genfcstab.
    292  * @todo: smaller, slower implementation for lower memory footprint?
    293  */
    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
    327 };
    328 
    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[] = {
    332   0x01,
    333   0x02,
    334   0x04,
    335   0x08,
    336   0x10,
    337   0x20,
    338   0x40,
    339   0x80
    340 };
    341 
    342 /** Wake up the task blocked in reading from serial line (if any) */
    343 static void
    344 pppRecvWakeup(int pd)
    345 {
    346   PPPDEBUG(LOG_DEBUG, ("pppRecvWakeup: unit %d\n", pd));
    347   if (pppControl[pd].openFlag != 0) {
    348     sio_read_abort(pppControl[pd].fd);
    349   }
    350 }
    351 #endif /* PPPOS_SUPPORT */
    352 
    353 void
    354 pppLinkTerminated(int pd)
    355 {
    356   PPPDEBUG(LOG_DEBUG, ("pppLinkTerminated: unit %d\n", pd));
    357 
    358 #if PPPOE_SUPPORT
    359   if (pppControl[pd].ethif) {
    360     pppoe_disconnect(pppControl[pd].pppoe_sc);
    361   } else
    362 #endif /* PPPOE_SUPPORT */
    363   {
    364 #if PPPOS_SUPPORT
    365     PPPControl* pc;
    366     pppRecvWakeup(pd);
    367     pc = &pppControl[pd];
    368 
    369     PPPDEBUG(LOG_DEBUG, ("pppLinkTerminated: unit %d: linkStatusCB=%p errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));
    370     if (pc->linkStatusCB) {
    371       pc->linkStatusCB(pc->linkStatusCtx, pc->errCode ? pc->errCode : PPPERR_PROTOCOL, NULL);
    372     }
    373 
    374     pc->openFlag = 0;/**/
    375 #endif /* PPPOS_SUPPORT */
    376   }
    377   PPPDEBUG(LOG_DEBUG, ("pppLinkTerminated: finished.\n"));
    378 }
    379 
    380 void
    381 pppLinkDown(int pd)
    382 {
    383   PPPDEBUG(LOG_DEBUG, ("pppLinkDown: unit %d\n", pd));
    384 
    385 #if PPPOE_SUPPORT
    386   if (pppControl[pd].ethif) {
    387     pppoe_disconnect(pppControl[pd].pppoe_sc);
    388   } else
    389 #endif /* PPPOE_SUPPORT */
    390   {
    391 #if PPPOS_SUPPORT
    392     pppRecvWakeup(pd);
    393 #endif /* PPPOS_SUPPORT */
    394   }
    395 }
    396 
    397 /** Initiate LCP open request */
    398 static void
    399 pppStart(int pd)
    400 {
    401   PPPDEBUG(LOG_DEBUG, ("pppStart: unit %d\n", pd));
    402   lcp_lowerup(pd);
    403   lcp_open(pd); /* Start protocol */
    404   PPPDEBUG(LOG_DEBUG, ("pppStart: finished\n"));
    405 }
    406 
    407 /** LCP close request */
    408 static void
    409 pppStop(int pd)
    410 {
    411   PPPDEBUG(LOG_DEBUG, ("pppStop: unit %d\n", pd));
    412   lcp_close(pd, "User request");
    413 }
    414 
    415 /** Called when carrier/link is lost */
    416 static void
    417 pppHup(int pd)
    418 {
    419   PPPDEBUG(LOG_DEBUG, ("pppHupCB: unit %d\n", pd));
    420   lcp_lowerdown(pd);
    421   link_terminated(pd);
    422 }
    423 
    424 /***********************************/
    425 /*** PUBLIC FUNCTION DEFINITIONS ***/
    426 /***********************************/
    427 /* Initialize the PPP subsystem. */
    428 
    429 struct ppp_settings ppp_settings;
    430 
    431 void
    432 pppInit(void)
    433 {
    434   struct protent *protp;
    435   int i, j;
    436 
    437   memset(&ppp_settings, 0, sizeof(ppp_settings));
    438   ppp_settings.usepeerdns = 1;
    439   pppSetAuth(PPPAUTHTYPE_NONE, NULL, NULL);
    440 
    441   magicInit();
    442 
    443   subnetMask = PP_HTONL(0xffffff00UL);
    444 
    445   for (i = 0; i < NUM_PPP; i++) {
    446     /* Initialize each protocol to the standard option set. */
    447     for (j = 0; (protp = ppp_protocols[j]) != NULL; ++j) {
    448       (*protp->init)(i);
    449     }
    450   }
    451 }
    452 
    453 void
    454 pppSetAuth(enum pppAuthType authType, const char *user, const char *passwd)
    455 {
    456   switch(authType) {
    457     case PPPAUTHTYPE_NONE:
    458     default:
    459 #ifdef LWIP_PPP_STRICT_PAP_REJECT
    460       ppp_settings.refuse_pap = 1;
    461 #else  /* LWIP_PPP_STRICT_PAP_REJECT */
    462       /* some providers request pap and accept an empty login/pw */
    463       ppp_settings.refuse_pap = 0;
    464 #endif /* LWIP_PPP_STRICT_PAP_REJECT */
    465       ppp_settings.refuse_chap = 1;
    466       break;
    467 
    468     case PPPAUTHTYPE_ANY:
    469       /* Warning: Using PPPAUTHTYPE_ANY might have security consequences.
    470        * RFC 1994 says:
    471        *
    472        * In practice, within or associated with each PPP server, there is a
    473        * database which associates "user" names with authentication
    474        * information ("secrets").  It is not anticipated that a particular
    475        * named user would be authenticated by multiple methods.  This would
    476        * make the user vulnerable to attacks which negotiate the least secure
    477        * method from among a set (such as PAP rather than CHAP).  If the same
    478        * secret was used, PAP would reveal the secret to be used later with
    479        * CHAP.
    480        *
    481        * Instead, for each user name there should be an indication of exactly
    482        * one method used to authenticate that user name.  If a user needs to
    483        * make use of different authentication methods under different
    484        * circumstances, then distinct user names SHOULD be employed, each of
    485        * which identifies exactly one authentication method.
    486        *
    487        */
    488       ppp_settings.refuse_pap = 0;
    489       ppp_settings.refuse_chap = 0;
    490       break;
    491 
    492     case PPPAUTHTYPE_PAP:
    493       ppp_settings.refuse_pap = 0;
    494       ppp_settings.refuse_chap = 1;
    495       break;
    496 
    497     case PPPAUTHTYPE_CHAP:
    498       ppp_settings.refuse_pap = 1;
    499       ppp_settings.refuse_chap = 0;
    500       break;
    501   }
    502 
    503   if(user) {
    504     strncpy(ppp_settings.user, user, sizeof(ppp_settings.user)-1);
    505     ppp_settings.user[sizeof(ppp_settings.user)-1] = '\0';
    506   } else {
    507     ppp_settings.user[0] = '\0';
    508   }
    509 
    510   if(passwd) {
    511     strncpy(ppp_settings.passwd, passwd, sizeof(ppp_settings.passwd)-1);
    512     ppp_settings.passwd[sizeof(ppp_settings.passwd)-1] = '\0';
    513   } else {
    514     ppp_settings.passwd[0] = '\0';
    515   }
    516 }
    517 
    518 #if PPPOS_SUPPORT
    519 /** Open a new PPP connection using the given I/O device.
    520  * This initializes the PPP control block but does not
    521  * attempt to negotiate the LCP session.  If this port
    522  * connects to a modem, the modem connection must be
    523  * established before calling this.
    524  * Return a new PPP connection descriptor on success or
    525  * an error code (negative) on failure.
    526  *
    527  * pppOpen() is directly defined to this function.
    528  */
    529 int
    530 pppOverSerialOpen(sio_fd_t fd, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx)
    531 {
    532   PPPControl *pc;
    533   int pd;
    534 
    535   if (linkStatusCB == NULL) {
    536     /* PPP is single-threaded: without a callback,
    537      * there is no way to know when the link is up. */
    538     return PPPERR_PARAM;
    539   }
    540 
    541   /* Find a free PPP session descriptor. */
    542   for (pd = 0; pd < NUM_PPP && pppControl[pd].openFlag != 0; pd++);
    543 
    544   if (pd >= NUM_PPP) {
    545     pd = PPPERR_OPEN;
    546   } else {
    547     pc = &pppControl[pd];
    548     /* @todo: is this correct or do I overwrite something? */
    549     memset(pc, 0, sizeof(PPPControl));
    550     pc->rx.pd = pd;
    551     pc->rx.fd = fd;
    552 
    553     pc->openFlag = 1;
    554     pc->fd = fd;
    555 
    556 #if VJ_SUPPORT
    557     vj_compress_init(&pc->vjComp);
    558 #endif /* VJ_SUPPORT */
    559 
    560     /*
    561      * Default the in and out accm so that escape and flag characters
    562      * are always escaped.
    563      */
    564     pc->rx.inACCM[15] = 0x60; /* no need to protect since RX is not running */
    565     pc->outACCM[15] = 0x60;
    566 
    567     pc->linkStatusCB = linkStatusCB;
    568     pc->linkStatusCtx = linkStatusCtx;
    569 
    570     /*
    571      * Start the connection and handle incoming events (packet or timeout).
    572      */
    573     PPPDEBUG(LOG_INFO, ("pppOverSerialOpen: unit %d: Connecting\n", pd));
    574     pppStart(pd);
    575 #if PPP_INPROC_OWNTHREAD
    576     sys_thread_new(PPP_THREAD_NAME, pppInputThread, (void*)&pc->rx, PPP_THREAD_STACKSIZE, PPP_THREAD_PRIO);
    577 #endif
    578   }
    579 
    580   return pd;
    581 }
    582 #endif /* PPPOS_SUPPORT */
    583 
    584 #if PPPOE_SUPPORT
    585 static void pppOverEthernetLinkStatusCB(int pd, int up);
    586 
    587 void
    588 pppOverEthernetClose(int pd)
    589 {
    590   PPPControl* pc = &pppControl[pd];
    591 
    592   /* *TJL* There's no lcp_deinit */
    593   lcp_close(pd, NULL);
    594 
    595   pppoe_destroy(&pc->netif);
    596 }
    597 
    598 int pppOverEthernetOpen(struct netif *ethif, const char *service_name, const char *concentrator_name, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx)
    599 {
    600   PPPControl *pc;
    601   int pd;
    602 
    603   LWIP_UNUSED_ARG(service_name);
    604   LWIP_UNUSED_ARG(concentrator_name);
    605 
    606   if (linkStatusCB == NULL) {
    607     /* PPP is single-threaded: without a callback,
    608      * there is no way to know when the link is up. */
    609     return PPPERR_PARAM;
    610   }
    611 
    612   /* Find a free PPP session descriptor. Critical region? */
    613   for (pd = 0; pd < NUM_PPP && pppControl[pd].openFlag != 0; pd++);
    614   if (pd >= NUM_PPP) {
    615     pd = PPPERR_OPEN;
    616   } else {
    617     pc = &pppControl[pd];
    618     memset(pc, 0, sizeof(PPPControl));
    619     pc->openFlag = 1;
    620     pc->ethif = ethif;
    621 
    622     pc->linkStatusCB  = linkStatusCB;
    623     pc->linkStatusCtx = linkStatusCtx;
    624 
    625     lcp_wantoptions[pd].mru = PPPOE_MAXMTU;
    626     lcp_wantoptions[pd].neg_asyncmap = 0;
    627     lcp_wantoptions[pd].neg_pcompression = 0;
    628     lcp_wantoptions[pd].neg_accompression = 0;
    629 
    630     lcp_allowoptions[pd].mru = PPPOE_MAXMTU;
    631     lcp_allowoptions[pd].neg_asyncmap = 0;
    632     lcp_allowoptions[pd].neg_pcompression = 0;
    633     lcp_allowoptions[pd].neg_accompression = 0;
    634 
    635     if(pppoe_create(ethif, pd, pppOverEthernetLinkStatusCB, &pc->pppoe_sc) != ERR_OK) {
    636       pc->openFlag = 0;
    637       return PPPERR_OPEN;
    638     }
    639 
    640     pppoe_connect(pc->pppoe_sc);
    641   }
    642 
    643   return pd;
    644 }
    645 #endif /* PPPOE_SUPPORT */
    646 
    647 
    648 /* Close a PPP connection and release the descriptor.
    649  * Any outstanding packets in the queues are dropped.
    650  * Return 0 on success, an error code on failure. */
    651 int
    652 pppClose(int pd)
    653 {
    654   PPPControl *pc = &pppControl[pd];
    655   int st = 0;
    656 
    657   PPPDEBUG(LOG_DEBUG, ("pppClose() called\n"));
    658 
    659   /* Disconnect */
    660 #if PPPOE_SUPPORT
    661   if(pc->ethif) {
    662     PPPDEBUG(LOG_DEBUG, ("pppClose: unit %d kill_link -> pppStop\n", pd));
    663     pc->errCode = PPPERR_USER;
    664     /* This will leave us at PHASE_DEAD. */
    665     pppStop(pd);
    666   } else
    667 #endif /* PPPOE_SUPPORT */
    668   {
    669 #if PPPOS_SUPPORT
    670     PPPDEBUG(LOG_DEBUG, ("pppClose: unit %d kill_link -> pppStop\n", pd));
    671     pc->errCode = PPPERR_USER;
    672     /* This will leave us at PHASE_DEAD. */
    673     pppStop(pd);
    674     pppRecvWakeup(pd);
    675 #endif /* PPPOS_SUPPORT */
    676   }
    677 
    678   return st;
    679 }
    680 
    681 /* This function is called when carrier is lost on the PPP channel. */
    682 void
    683 pppSigHUP(int pd)
    684 {
    685   PPPDEBUG(LOG_DEBUG, ("pppSigHUP: unit %d sig_hup -> pppHupCB\n", pd));
    686   pppHup(pd);
    687 }
    688 
    689 #if PPPOS_SUPPORT
    690 static void
    691 nPut(PPPControl *pc, struct pbuf *nb)
    692 {
    693   struct pbuf *b;
    694   int c;
    695 
    696   for(b = nb; b != NULL; b = b->next) {
    697     if((c = sio_write(pc->fd, b->payload, b->len)) != b->len) {
    698       PPPDEBUG(LOG_WARNING,
    699                ("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));
    700       LINK_STATS_INC(link.err);
    701       pc->lastXMit = 0; /* prepend PPP_FLAG to next packet */
    702       snmp_inc_ifoutdiscards(&pc->netif);
    703       pbuf_free(nb);
    704       return;
    705     }
    706   }
    707 
    708   snmp_add_ifoutoctets(&pc->netif, nb->tot_len);
    709   snmp_inc_ifoutucastpkts(&pc->netif);
    710   pbuf_free(nb);
    711   LINK_STATS_INC(link.xmit);
    712 }
    713 
    714 /*
    715  * pppAppend - append given character to end of given pbuf.  If outACCM
    716  * is not NULL and the character needs to be escaped, do so.
    717  * If pbuf is full, append another.
    718  * Return the current pbuf.
    719  */
    720 static struct pbuf *
    721 pppAppend(u_char c, struct pbuf *nb, ext_accm *outACCM)
    722 {
    723   struct pbuf *tb = nb;
    724 
    725   /* Make sure there is room for the character and an escape code.
    726    * Sure we don't quite fill the buffer if the character doesn't
    727    * get escaped but is one character worth complicating this? */
    728   /* Note: We assume no packet header. */
    729   if (nb && (PBUF_POOL_BUFSIZE - nb->len) < 2) {
    730     tb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
    731     if (tb) {
    732       nb->next = tb;
    733     } else {
    734       LINK_STATS_INC(link.memerr);
    735     }
    736     nb = tb;
    737   }
    738 
    739   if (nb) {
    740     if (outACCM && ESCAPE_P(*outACCM, c)) {
    741       *((u_char*)nb->payload + nb->len++) = PPP_ESCAPE;
    742       *((u_char*)nb->payload + nb->len++) = c ^ PPP_TRANS;
    743     } else {
    744       *((u_char*)nb->payload + nb->len++) = c;
    745     }
    746   }
    747 
    748   return tb;
    749 }
    750 #endif /* PPPOS_SUPPORT */
    751 
    752 #if PPPOE_SUPPORT
    753 static err_t
    754 pppifOutputOverEthernet(int pd, struct pbuf *p)
    755 {
    756   PPPControl *pc = &pppControl[pd];
    757   struct pbuf *pb;
    758   u_short protocol = PPP_IP;
    759   int i=0;
    760   u16_t tot_len;
    761 
    762   /* @todo: try to use pbuf_header() here! */
    763   pb = pbuf_alloc(PBUF_LINK, PPPOE_HDRLEN + sizeof(protocol), PBUF_RAM);
    764   if(!pb) {
    765     LINK_STATS_INC(link.memerr);
    766     LINK_STATS_INC(link.proterr);
    767     snmp_inc_ifoutdiscards(&pc->netif);
    768     return ERR_MEM;
    769   }
    770 
    771   pbuf_header(pb, -(s16_t)PPPOE_HDRLEN);
    772 
    773   pc->lastXMit = sys_jiffies();
    774 
    775   if (!pc->pcomp || protocol > 0xFF) {
    776     *((u_char*)pb->payload + i++) = (protocol >> 8) & 0xFF;
    777   }
    778   *((u_char*)pb->payload + i) = protocol & 0xFF;
    779 
    780   pbuf_chain(pb, p);
    781   tot_len = pb->tot_len;
    782 
    783   if(pppoe_xmit(pc->pppoe_sc, pb) != ERR_OK) {
    784     LINK_STATS_INC(link.err);
    785     snmp_inc_ifoutdiscards(&pc->netif);
    786     return PPPERR_DEVICE;
    787   }
    788 
    789   snmp_add_ifoutoctets(&pc->netif, tot_len);
    790   snmp_inc_ifoutucastpkts(&pc->netif);
    791   LINK_STATS_INC(link.xmit);
    792   return ERR_OK;
    793 }
    794 #endif /* PPPOE_SUPPORT */
    795 
    796 /* Send a packet on the given connection. */
    797 static err_t
    798 pppifOutput(struct netif *netif, struct pbuf *pb, ip_addr_t *ipaddr)
    799 {
    800   int pd = (int)(size_t)netif->state;
    801   PPPControl *pc = &pppControl[pd];
    802 #if PPPOS_SUPPORT
    803   u_short protocol = PPP_IP;
    804   u_int fcsOut = PPP_INITFCS;
    805   struct pbuf *headMB = NULL, *tailMB = NULL, *p;
    806   u_char c;
    807 #endif /* PPPOS_SUPPORT */
    808 
    809   LWIP_UNUSED_ARG(ipaddr);
    810 
    811   /* Validate parameters. */
    812   /* We let any protocol value go through - it can't hurt us
    813    * and the peer will just drop it if it's not accepting it. */
    814   if (pd < 0 || pd >= NUM_PPP || !pc->openFlag || !pb) {
    815     PPPDEBUG(LOG_WARNING, ("pppifOutput[%d]: bad parms prot=%d pb=%p\n",
    816               pd, PPP_IP, pb));
    817     LINK_STATS_INC(link.opterr);
    818     LINK_STATS_INC(link.drop);
    819     snmp_inc_ifoutdiscards(netif);
    820     return ERR_ARG;
    821   }
    822 
    823   /* Check that the link is up. */
    824   if (lcp_phase[pd] == PHASE_DEAD) {
    825     PPPDEBUG(LOG_ERR, ("pppifOutput[%d]: link not up\n", pd));
    826     LINK_STATS_INC(link.rterr);
    827     LINK_STATS_INC(link.drop);
    828     snmp_inc_ifoutdiscards(netif);
    829     return ERR_RTE;
    830   }
    831 
    832 #if PPPOE_SUPPORT
    833   if(pc->ethif) {
    834     return pppifOutputOverEthernet(pd, pb);
    835   }
    836 #endif /* PPPOE_SUPPORT */
    837 
    838 #if PPPOS_SUPPORT
    839   /* Grab an output buffer. */
    840   headMB = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
    841   if (headMB == NULL) {
    842     PPPDEBUG(LOG_WARNING, ("pppifOutput[%d]: first alloc fail\n", pd));
    843     LINK_STATS_INC(link.memerr);
    844     LINK_STATS_INC(link.drop);
    845     snmp_inc_ifoutdiscards(netif);
    846     return ERR_MEM;
    847   }
    848 
    849 #if VJ_SUPPORT
    850   /*
    851    * Attempt Van Jacobson header compression if VJ is configured and
    852    * this is an IP packet.
    853    */
    854   if (protocol == PPP_IP && pc->vjEnabled) {
    855     switch (vj_compress_tcp(&pc->vjComp, pb)) {
    856       case TYPE_IP:
    857         /* No change...
    858            protocol = PPP_IP_PROTOCOL; */
    859         break;
    860       case TYPE_COMPRESSED_TCP:
    861         protocol = PPP_VJC_COMP;
    862         break;
    863       case TYPE_UNCOMPRESSED_TCP:
    864         protocol = PPP_VJC_UNCOMP;
    865         break;
    866       default:
    867         PPPDEBUG(LOG_WARNING, ("pppifOutput[%d]: bad IP packet\n", pd));
    868         LINK_STATS_INC(link.proterr);
    869         LINK_STATS_INC(link.drop);
    870         snmp_inc_ifoutdiscards(netif);
    871         pbuf_free(headMB);
    872         return ERR_VAL;
    873     }
    874   }
    875 #endif /* VJ_SUPPORT */
    876 
    877   tailMB = headMB;
    878 
    879   /* Build the PPP header. */
    880   if ((sys_jiffies() - pc->lastXMit) >= PPP_MAXIDLEFLAG) {
    881     tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
    882   }
    883 
    884   pc->lastXMit = sys_jiffies();
    885   if (!pc->accomp) {
    886     fcsOut = PPP_FCS(fcsOut, PPP_ALLSTATIONS);
    887     tailMB = pppAppend(PPP_ALLSTATIONS, tailMB, &pc->outACCM);
    888     fcsOut = PPP_FCS(fcsOut, PPP_UI);
    889     tailMB = pppAppend(PPP_UI, tailMB, &pc->outACCM);
    890   }
    891   if (!pc->pcomp || protocol > 0xFF) {
    892     c = (protocol >> 8) & 0xFF;
    893     fcsOut = PPP_FCS(fcsOut, c);
    894     tailMB = pppAppend(c, tailMB, &pc->outACCM);
    895   }
    896   c = protocol & 0xFF;
    897   fcsOut = PPP_FCS(fcsOut, c);
    898   tailMB = pppAppend(c, tailMB, &pc->outACCM);
    899 
    900   /* Load packet. */
    901   for(p = pb; p; p = p->next) {
    902     int n;
    903     u_char *sPtr;
    904 
    905     sPtr = (u_char*)p->payload;
    906     n = p->len;
    907     while (n-- > 0) {
    908       c = *sPtr++;
    909 
    910       /* Update FCS before checking for special characters. */
    911       fcsOut = PPP_FCS(fcsOut, c);
    912 
    913       /* Copy to output buffer escaping special characters. */
    914       tailMB = pppAppend(c, tailMB, &pc->outACCM);
    915     }
    916   }
    917 
    918   /* Add FCS and trailing flag. */
    919   c = ~fcsOut & 0xFF;
    920   tailMB = pppAppend(c, tailMB, &pc->outACCM);
    921   c = (~fcsOut >> 8) & 0xFF;
    922   tailMB = pppAppend(c, tailMB, &pc->outACCM);
    923   tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
    924 
    925   /* If we failed to complete the packet, throw it away. */
    926   if (!tailMB) {
    927     PPPDEBUG(LOG_WARNING,
    928              ("pppifOutput[%d]: Alloc err - dropping proto=%d\n",
    929               pd, protocol));
    930     pbuf_free(headMB);
    931     LINK_STATS_INC(link.memerr);
    932     LINK_STATS_INC(link.drop);
    933     snmp_inc_ifoutdiscards(netif);
    934     return ERR_MEM;
    935   }
    936 
    937   /* Send it. */
    938   PPPDEBUG(LOG_INFO, ("pppifOutput[%d]: proto=0x%"X16_F"\n", pd, protocol));
    939 
    940   nPut(pc, headMB);
    941 #endif /* PPPOS_SUPPORT */
    942 
    943   return ERR_OK;
    944 }
    945 
    946 /* Get and set parameters for the given connection.
    947  * Return 0 on success, an error code on failure. */
    948 int
    949 pppIOCtl(int pd, int cmd, void *arg)
    950 {
    951   PPPControl *pc = &pppControl[pd];
    952   int st = 0;
    953 
    954   if (pd < 0 || pd >= NUM_PPP) {
    955     st = PPPERR_PARAM;
    956   } else {
    957     switch(cmd) {
    958     case PPPCTLG_UPSTATUS:      /* Get the PPP up status. */
    959       if (arg) {
    960         *(int *)arg = (int)(pc->if_up);
    961       } else {
    962         st = PPPERR_PARAM;
    963       }
    964       break;
    965     case PPPCTLS_ERRCODE:       /* Set the PPP error code. */
    966       if (arg) {
    967         pc->errCode = *(int *)arg;
    968       } else {
    969         st = PPPERR_PARAM;
    970       }
    971       break;
    972     case PPPCTLG_ERRCODE:       /* Get the PPP error code. */
    973       if (arg) {
    974         *(int *)arg = (int)(pc->errCode);
    975       } else {
    976         st = PPPERR_PARAM;
    977       }
    978       break;
    979 #if PPPOS_SUPPORT
    980     case PPPCTLG_FD:            /* Get the fd associated with the ppp */
    981       if (arg) {
    982         *(sio_fd_t *)arg = pc->fd;
    983       } else {
    984         st = PPPERR_PARAM;
    985       }
    986       break;
    987 #endif /* PPPOS_SUPPORT */
    988     default:
    989       st = PPPERR_PARAM;
    990       break;
    991     }
    992   }
    993 
    994   return st;
    995 }
    996 
    997 /*
    998  * Return the Maximum Transmission Unit for the given PPP connection.
    999  */
   1000 u_short
   1001 pppMTU(int pd)
   1002 {
   1003   PPPControl *pc = &pppControl[pd];
   1004   u_short st;
   1005 
   1006   /* Validate parameters. */
   1007   if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
   1008     st = 0;
   1009   } else {
   1010     st = pc->mtu;
   1011   }
   1012 
   1013   return st;
   1014 }
   1015 
   1016 #if PPPOE_SUPPORT
   1017 int
   1018 pppWriteOverEthernet(int pd, const u_char *s, int n)
   1019 {
   1020   PPPControl *pc = &pppControl[pd];
   1021   struct pbuf *pb;
   1022 
   1023   /* skip address & flags */
   1024   s += 2;
   1025   n -= 2;
   1026 
   1027   LWIP_ASSERT("PPPOE_HDRLEN + n <= 0xffff", PPPOE_HDRLEN + n <= 0xffff);
   1028   pb = pbuf_alloc(PBUF_LINK, (u16_t)(PPPOE_HDRLEN + n), PBUF_RAM);
   1029   if(!pb) {
   1030     LINK_STATS_INC(link.memerr);
   1031     LINK_STATS_INC(link.proterr);
   1032     snmp_inc_ifoutdiscards(&pc->netif);
   1033     return PPPERR_ALLOC;
   1034   }
   1035 
   1036   pbuf_header(pb, -(s16_t)PPPOE_HDRLEN);
   1037 
   1038   pc->lastXMit = sys_jiffies();
   1039 
   1040   MEMCPY(pb->payload, s, n);
   1041 
   1042   if(pppoe_xmit(pc->pppoe_sc, pb) != ERR_OK) {
   1043     LINK_STATS_INC(link.err);
   1044     snmp_inc_ifoutdiscards(&pc->netif);
   1045     return PPPERR_DEVICE;
   1046   }
   1047 
   1048   snmp_add_ifoutoctets(&pc->netif, (u16_t)n);
   1049   snmp_inc_ifoutucastpkts(&pc->netif);
   1050   LINK_STATS_INC(link.xmit);
   1051   return PPPERR_NONE;
   1052 }
   1053 #endif /* PPPOE_SUPPORT */
   1054 
   1055 /*
   1056  * Write n characters to a ppp link.
   1057  *  RETURN: >= 0 Number of characters written
   1058  *           -1 Failed to write to device
   1059  */
   1060 int
   1061 pppWrite(int pd, const u_char *s, int n)
   1062 {
   1063   PPPControl *pc = &pppControl[pd];
   1064 #if PPPOS_SUPPORT
   1065   u_char c;
   1066   u_int fcsOut;
   1067   struct pbuf *headMB, *tailMB;
   1068 #endif /* PPPOS_SUPPORT */
   1069 
   1070 #if PPPOE_SUPPORT
   1071   if(pc->ethif) {
   1072     return pppWriteOverEthernet(pd, s, n);
   1073   }
   1074 #endif /* PPPOE_SUPPORT */
   1075 
   1076 #if PPPOS_SUPPORT
   1077   headMB = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
   1078   if (headMB == NULL) {
   1079     LINK_STATS_INC(link.memerr);
   1080     LINK_STATS_INC(link.proterr);
   1081     snmp_inc_ifoutdiscards(&pc->netif);
   1082     return PPPERR_ALLOC;
   1083   }
   1084 
   1085   tailMB = headMB;
   1086 
   1087   /* If the link has been idle, we'll send a fresh flag character to
   1088    * flush any noise. */
   1089   if ((sys_jiffies() - pc->lastXMit) >= PPP_MAXIDLEFLAG) {
   1090     tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
   1091   }
   1092   pc->lastXMit = sys_jiffies();
   1093 
   1094   fcsOut = PPP_INITFCS;
   1095   /* Load output buffer. */
   1096   while (n-- > 0) {
   1097     c = *s++;
   1098 
   1099     /* Update FCS before checking for special characters. */
   1100     fcsOut = PPP_FCS(fcsOut, c);
   1101 
   1102     /* Copy to output buffer escaping special characters. */
   1103     tailMB = pppAppend(c, tailMB, &pc->outACCM);
   1104   }
   1105 
   1106   /* Add FCS and trailing flag. */
   1107   c = ~fcsOut & 0xFF;
   1108   tailMB = pppAppend(c, tailMB, &pc->outACCM);
   1109   c = (~fcsOut >> 8) & 0xFF;
   1110   tailMB = pppAppend(c, tailMB, &pc->outACCM);
   1111   tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
   1112 
   1113   /* If we failed to complete the packet, throw it away.
   1114    * Otherwise send it. */
   1115   if (!tailMB) {
   1116     PPPDEBUG(LOG_WARNING,
   1117              ("pppWrite[%d]: Alloc err - dropping pbuf len=%d\n", pd, headMB->len));
   1118            /*"pppWrite[%d]: Alloc err - dropping %d:%.*H", pd, headMB->len, LWIP_MIN(headMB->len * 2, 40), headMB->payload)); */
   1119     pbuf_free(headMB);
   1120     LINK_STATS_INC(link.memerr);
   1121     LINK_STATS_INC(link.proterr);
   1122     snmp_inc_ifoutdiscards(&pc->netif);
   1123     return PPPERR_ALLOC;
   1124   }
   1125 
   1126   PPPDEBUG(LOG_INFO, ("pppWrite[%d]: len=%d\n", pd, headMB->len));
   1127                    /* "pppWrite[%d]: %d:%.*H", pd, headMB->len, LWIP_MIN(headMB->len * 2, 40), headMB->payload)); */
   1128   nPut(pc, headMB);
   1129 #endif /* PPPOS_SUPPORT */
   1130 
   1131   return PPPERR_NONE;
   1132 }
   1133 
   1134 /*
   1135  * ppp_send_config - configure the transmit characteristics of
   1136  * the ppp interface.
   1137  */
   1138 void
   1139 ppp_send_config( int unit, u16_t mtu, u32_t asyncmap, int pcomp, int accomp)
   1140 {
   1141   PPPControl *pc = &pppControl[unit];
   1142   int i;
   1143 
   1144   pc->mtu = mtu;
   1145   pc->pcomp = pcomp;
   1146   pc->accomp = accomp;
   1147 
   1148   /* Load the ACCM bits for the 32 control codes. */
   1149   for (i = 0; i < 32/8; i++) {
   1150     pc->outACCM[i] = (u_char)((asyncmap >> (8 * i)) & 0xFF);
   1151   }
   1152   PPPDEBUG(LOG_INFO, ("ppp_send_config[%d]: outACCM=%X %X %X %X\n",
   1153             unit,
   1154             pc->outACCM[0], pc->outACCM[1], pc->outACCM[2], pc->outACCM[3]));
   1155 }
   1156 
   1157 
   1158 /*
   1159  * ppp_set_xaccm - set the extended transmit ACCM for the interface.
   1160  */
   1161 void
   1162 ppp_set_xaccm(int unit, ext_accm *accm)
   1163 {
   1164   SMEMCPY(pppControl[unit].outACCM, accm, sizeof(ext_accm));
   1165   PPPDEBUG(LOG_INFO, ("ppp_set_xaccm[%d]: outACCM=%X %X %X %X\n",
   1166             unit,
   1167             pppControl[unit].outACCM[0],
   1168             pppControl[unit].outACCM[1],
   1169             pppControl[unit].outACCM[2],
   1170             pppControl[unit].outACCM[3]));
   1171 }
   1172 
   1173 
   1174 /*
   1175  * ppp_recv_config - configure the receive-side characteristics of
   1176  * the ppp interface.
   1177  */
   1178 void
   1179 ppp_recv_config( int unit, int mru, u32_t asyncmap, int pcomp, int accomp)
   1180 {
   1181   PPPControl *pc = &pppControl[unit];
   1182   int i;
   1183   SYS_ARCH_DECL_PROTECT(lev);
   1184 
   1185   LWIP_UNUSED_ARG(accomp);
   1186   LWIP_UNUSED_ARG(pcomp);
   1187   LWIP_UNUSED_ARG(mru);
   1188 
   1189   /* Load the ACCM bits for the 32 control codes. */
   1190   SYS_ARCH_PROTECT(lev);
   1191   for (i = 0; i < 32 / 8; i++) {
   1192     /* @todo: does this work? ext_accm has been modified from pppd! */
   1193     pc->rx.inACCM[i] = (u_char)(asyncmap >> (i * 8));
   1194   }
   1195   SYS_ARCH_UNPROTECT(lev);
   1196   PPPDEBUG(LOG_INFO, ("ppp_recv_config[%d]: inACCM=%X %X %X %X\n",
   1197             unit,
   1198             pc->rx.inACCM[0], pc->rx.inACCM[1], pc->rx.inACCM[2], pc->rx.inACCM[3]));
   1199 }
   1200 
   1201 #if 0
   1202 /*
   1203  * ccp_test - ask kernel whether a given compression method
   1204  * is acceptable for use.  Returns 1 if the method and parameters
   1205  * are OK, 0 if the method is known but the parameters are not OK
   1206  * (e.g. code size should be reduced), or -1 if the method is unknown.
   1207  */
   1208 int
   1209 ccp_test( int unit, int opt_len,  int for_transmit, u_char *opt_ptr)
   1210 {
   1211   return 0; /* XXX Currently no compression. */
   1212 }
   1213 
   1214 /*
   1215  * ccp_flags_set - inform kernel about the current state of CCP.
   1216  */
   1217 void
   1218 ccp_flags_set(int unit, int isopen, int isup)
   1219 {
   1220   /* XXX */
   1221 }
   1222 
   1223 /*
   1224  * ccp_fatal_error - returns 1 if decompression was disabled as a
   1225  * result of an error detected after decompression of a packet,
   1226  * 0 otherwise.  This is necessary because of patent nonsense.
   1227  */
   1228 int
   1229 ccp_fatal_error(int unit)
   1230 {
   1231   /* XXX */
   1232   return 0;
   1233 }
   1234 #endif
   1235 
   1236 /*
   1237  * get_idle_time - return how long the link has been idle.
   1238  */
   1239 int
   1240 get_idle_time(int u, struct ppp_idle *ip)
   1241 {
   1242   /* XXX */
   1243   LWIP_UNUSED_ARG(u);
   1244   LWIP_UNUSED_ARG(ip);
   1245 
   1246   return 0;
   1247 }
   1248 
   1249 
   1250 /*
   1251  * Return user specified netmask, modified by any mask we might determine
   1252  * for address `addr' (in network byte order).
   1253  * Here we scan through the system's list of interfaces, looking for
   1254  * any non-point-to-point interfaces which might appear to be on the same
   1255  * network as `addr'.  If we find any, we OR in their netmask to the
   1256  * user-specified netmask.
   1257  */
   1258 u32_t
   1259 GetMask(u32_t addr)
   1260 {
   1261   u32_t mask, nmask;
   1262 
   1263   htonl(addr);
   1264   if (IP_CLASSA(addr)) { /* determine network mask for address class */
   1265     nmask = IP_CLASSA_NET;
   1266   } else if (IP_CLASSB(addr)) {
   1267     nmask = IP_CLASSB_NET;
   1268   } else {
   1269     nmask = IP_CLASSC_NET;
   1270   }
   1271 
   1272   /* class D nets are disallowed by bad_ip_adrs */
   1273   mask = subnetMask | htonl(nmask);
   1274 
   1275   /* XXX
   1276    * Scan through the system's network interfaces.
   1277    * Get each netmask and OR them into our mask.
   1278    */
   1279 
   1280   return mask;
   1281 }
   1282 
   1283 /*
   1284  * sifvjcomp - config tcp header compression
   1285  */
   1286 int
   1287 sifvjcomp(int pd, int vjcomp, u8_t cidcomp, u8_t maxcid)
   1288 {
   1289 #if PPPOS_SUPPORT && VJ_SUPPORT
   1290   PPPControl *pc = &pppControl[pd];
   1291 
   1292   pc->vjEnabled = vjcomp;
   1293   pc->vjComp.compressSlot = cidcomp;
   1294   pc->vjComp.maxSlotIndex = maxcid;
   1295   PPPDEBUG(LOG_INFO, ("sifvjcomp: VJ compress enable=%d slot=%d max slot=%d\n",
   1296             vjcomp, cidcomp, maxcid));
   1297 #else /* PPPOS_SUPPORT && VJ_SUPPORT */
   1298   LWIP_UNUSED_ARG(pd);
   1299   LWIP_UNUSED_ARG(vjcomp);
   1300   LWIP_UNUSED_ARG(cidcomp);
   1301   LWIP_UNUSED_ARG(maxcid);
   1302 #endif /* PPPOS_SUPPORT && VJ_SUPPORT */
   1303 
   1304   return 0;
   1305 }
   1306 
   1307 /*
   1308  * pppifNetifInit - netif init callback
   1309  */
   1310 static err_t
   1311 pppifNetifInit(struct netif *netif)
   1312 {
   1313   netif->name[0] = 'p';
   1314   netif->name[1] = 'p';
   1315   netif->output = pppifOutput;
   1316   netif->mtu = pppMTU((int)(size_t)netif->state);
   1317   netif->flags = NETIF_FLAG_POINTTOPOINT | NETIF_FLAG_LINK_UP;
   1318 #if LWIP_NETIF_HOSTNAME
   1319   /* @todo: Initialize interface hostname */
   1320   /* netif_set_hostname(netif, "lwip"); */
   1321 #endif /* LWIP_NETIF_HOSTNAME */
   1322   return ERR_OK;
   1323 }
   1324 
   1325 
   1326 /*
   1327  * sifup - Config the interface up and enable IP packets to pass.
   1328  */
   1329 int
   1330 sifup(int pd)
   1331 {
   1332   PPPControl *pc = &pppControl[pd];
   1333   int st = 1;
   1334 
   1335   if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
   1336     st = 0;
   1337     PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd));
   1338   } else {
   1339     netif_remove(&pc->netif);
   1340     if (netif_add(&pc->netif, &pc->addrs.our_ipaddr, &pc->addrs.netmask,
   1341                   &pc->addrs.his_ipaddr, (void *)(size_t)pd, pppifNetifInit, ip_input)) {
   1342       netif_set_up(&pc->netif);
   1343       pc->if_up = 1;
   1344       pc->errCode = PPPERR_NONE;
   1345 
   1346       PPPDEBUG(LOG_DEBUG, ("sifup: unit %d: linkStatusCB=%p errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));
   1347       if (pc->linkStatusCB) {
   1348         pc->linkStatusCB(pc->linkStatusCtx, pc->errCode, &pc->addrs);
   1349       }
   1350     } else {
   1351       st = 0;
   1352       PPPDEBUG(LOG_ERR, ("sifup[%d]: netif_add failed\n", pd));
   1353     }
   1354   }
   1355 
   1356   return st;
   1357 }
   1358 
   1359 /*
   1360  * sifnpmode - Set the mode for handling packets for a given NP.
   1361  */
   1362 int
   1363 sifnpmode(int u, int proto, enum NPmode mode)
   1364 {
   1365   LWIP_UNUSED_ARG(u);
   1366   LWIP_UNUSED_ARG(proto);
   1367   LWIP_UNUSED_ARG(mode);
   1368   return 0;
   1369 }
   1370 
   1371 /*
   1372  * sifdown - Config the interface down and disable IP.
   1373  */
   1374 int
   1375 sifdown(int pd)
   1376 {
   1377   PPPControl *pc = &pppControl[pd];
   1378   int st = 1;
   1379 
   1380   if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
   1381     st = 0;
   1382     PPPDEBUG(LOG_WARNING, ("sifdown[%d]: bad parms\n", pd));
   1383   } else {
   1384     pc->if_up = 0;
   1385     /* make sure the netif status callback is called */
   1386     netif_set_down(&pc->netif);
   1387     netif_remove(&pc->netif);
   1388     PPPDEBUG(LOG_DEBUG, ("sifdown: unit %d: linkStatusCB=%p errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));
   1389     if (pc->linkStatusCB) {
   1390       pc->linkStatusCB(pc->linkStatusCtx, PPPERR_CONNECT, NULL);
   1391     }
   1392   }
   1393   return st;
   1394 }
   1395 
   1396 /**
   1397  * sifaddr - Config the interface IP addresses and netmask.
   1398  * @param pd Interface unit ???
   1399  * @param o Our IP address ???
   1400  * @param h His IP address ???
   1401  * @param m IP subnet mask ???
   1402  * @param ns1 Primary DNS
   1403  * @param ns2 Secondary DNS
   1404  */
   1405 int
   1406 sifaddr( int pd, u32_t o, u32_t h, u32_t m, u32_t ns1, u32_t ns2)
   1407 {
   1408   PPPControl *pc = &pppControl[pd];
   1409   int st = 1;
   1410 
   1411   if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
   1412     st = 0;
   1413     PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd));
   1414   } else {
   1415     SMEMCPY(&pc->addrs.our_ipaddr, &o, sizeof(o));
   1416     SMEMCPY(&pc->addrs.his_ipaddr, &h, sizeof(h));
   1417     SMEMCPY(&pc->addrs.netmask, &m, sizeof(m));
   1418     SMEMCPY(&pc->addrs.dns1, &ns1, sizeof(ns1));
   1419     SMEMCPY(&pc->addrs.dns2, &ns2, sizeof(ns2));
   1420   }
   1421   return st;
   1422 }
   1423 
   1424 /**
   1425  * cifaddr - Clear the interface IP addresses, and delete routes
   1426  * through the interface if possible.
   1427  * @param pd Interface unit ???
   1428  * @param o Our IP address ???
   1429  * @param h IP broadcast address ???
   1430  */
   1431 int
   1432 cifaddr( int pd, u32_t o, u32_t h)
   1433 {
   1434   PPPControl *pc = &pppControl[pd];
   1435   int st = 1;
   1436 
   1437   LWIP_UNUSED_ARG(o);
   1438   LWIP_UNUSED_ARG(h);
   1439   if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
   1440     st = 0;
   1441     PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd));
   1442   } else {
   1443     IP4_ADDR(&pc->addrs.our_ipaddr, 0,0,0,0);
   1444     IP4_ADDR(&pc->addrs.his_ipaddr, 0,0,0,0);
   1445     IP4_ADDR(&pc->addrs.netmask, 255,255,255,0);
   1446     IP4_ADDR(&pc->addrs.dns1, 0,0,0,0);
   1447     IP4_ADDR(&pc->addrs.dns2, 0,0,0,0);
   1448   }
   1449   return st;
   1450 }
   1451 
   1452 /*
   1453  * sifdefaultroute - assign a default route through the address given.
   1454  */
   1455 int
   1456 sifdefaultroute(int pd, u32_t l, u32_t g)
   1457 {
   1458   PPPControl *pc = &pppControl[pd];
   1459   int st = 1;
   1460 
   1461   LWIP_UNUSED_ARG(l);
   1462   LWIP_UNUSED_ARG(g);
   1463 
   1464   if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
   1465     st = 0;
   1466     PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd));
   1467   } else {
   1468     netif_set_default(&pc->netif);
   1469   }
   1470 
   1471   /* TODO: check how PPP handled the netMask, previously not set by ipSetDefault */
   1472 
   1473   return st;
   1474 }
   1475 
   1476 /*
   1477  * cifdefaultroute - delete a default route through the address given.
   1478  */
   1479 int
   1480 cifdefaultroute(int pd, u32_t l, u32_t g)
   1481 {
   1482   PPPControl *pc = &pppControl[pd];
   1483   int st = 1;
   1484 
   1485   LWIP_UNUSED_ARG(l);
   1486   LWIP_UNUSED_ARG(g);
   1487 
   1488   if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
   1489     st = 0;
   1490     PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd));
   1491   } else {
   1492     netif_set_default(NULL);
   1493   }
   1494 
   1495   return st;
   1496 }
   1497 
   1498 /**********************************/
   1499 /*** LOCAL FUNCTION DEFINITIONS ***/
   1500 /**********************************/
   1501 
   1502 #if PPPOS_SUPPORT && PPP_INPROC_OWNTHREAD
   1503 /* The main PPP process function.  This implements the state machine according
   1504  * to section 4 of RFC 1661: The Point-To-Point Protocol. */
   1505 static void
   1506 pppInputThread(void *arg)
   1507 {
   1508   int count;
   1509   PPPControlRx *pcrx = arg;
   1510 
   1511   while (lcp_phase[pcrx->pd] != PHASE_DEAD) {
   1512     count = sio_read(pcrx->fd, pcrx->rxbuf, PPPOS_RX_BUFSIZE);
   1513     if(count > 0) {
   1514       pppInProc(pcrx, pcrx->rxbuf, count);
   1515     } else {
   1516       /* nothing received, give other tasks a chance to run */
   1517       sys_msleep(1);
   1518     }
   1519   }
   1520 }
   1521 #endif /* PPPOS_SUPPORT && PPP_INPROC_OWNTHREAD */
   1522 
   1523 #if PPPOE_SUPPORT
   1524 
   1525 void
   1526 pppOverEthernetInitFailed(int pd)
   1527 {
   1528   PPPControl* pc;
   1529 
   1530   pppHup(pd);
   1531   pppStop(pd);
   1532 
   1533   pc = &pppControl[pd];
   1534   pppoe_destroy(&pc->netif);
   1535   pc->openFlag = 0;
   1536 
   1537   if(pc->linkStatusCB) {
   1538     pc->linkStatusCB(pc->linkStatusCtx, pc->errCode ? pc->errCode : PPPERR_PROTOCOL, NULL);
   1539   }
   1540 }
   1541 
   1542 static void
   1543 pppOverEthernetLinkStatusCB(int pd, int up)
   1544 {
   1545   if(up) {
   1546     PPPDEBUG(LOG_INFO, ("pppOverEthernetLinkStatusCB: unit %d: Connecting\n", pd));
   1547     pppStart(pd);
   1548   } else {
   1549     pppOverEthernetInitFailed(pd);
   1550   }
   1551 }
   1552 #endif /* PPPOE_SUPPORT */
   1553 
   1554 struct pbuf *
   1555 pppSingleBuf(struct pbuf *p)
   1556 {
   1557   struct pbuf *q, *b;
   1558   u_char *pl;
   1559 
   1560   if(p->tot_len == p->len) {
   1561     return p;
   1562   }
   1563 
   1564   q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
   1565   if(!q) {
   1566     PPPDEBUG(LOG_ERR,
   1567              ("pppSingleBuf: unable to alloc new buf (%d)\n", p->tot_len));
   1568     return p; /* live dangerously */
   1569   }
   1570 
   1571   for(b = p, pl = q->payload; b != NULL; b = b->next) {
   1572     MEMCPY(pl, b->payload, b->len);
   1573     pl += b->len;
   1574   }
   1575 
   1576   pbuf_free(p);
   1577 
   1578   return q;
   1579 }
   1580 
   1581 struct pppInputHeader {
   1582   int unit;
   1583   u16_t proto;
   1584 };
   1585 
   1586 /*
   1587  * Pass the processed input packet to the appropriate handler.
   1588  * This function and all handlers run in the context of the tcpip_thread
   1589  */
   1590 static void
   1591 pppInput(void *arg)
   1592 {
   1593   struct pbuf *nb = (struct pbuf *)arg;
   1594   u16_t protocol;
   1595   int pd;
   1596 
   1597   pd = ((struct pppInputHeader *)nb->payload)->unit;
   1598   protocol = ((struct pppInputHeader *)nb->payload)->proto;
   1599 
   1600   if(pbuf_header(nb, -(int)sizeof(struct pppInputHeader))) {
   1601     LWIP_ASSERT("pbuf_header failed\n", 0);
   1602     goto drop;
   1603   }
   1604 
   1605   LINK_STATS_INC(link.recv);
   1606   snmp_inc_ifinucastpkts(&pppControl[pd].netif);
   1607   snmp_add_ifinoctets(&pppControl[pd].netif, nb->tot_len);
   1608 
   1609   /*
   1610    * Toss all non-LCP packets unless LCP is OPEN.
   1611    * Until we get past the authentication phase, toss all packets
   1612    * except LCP, LQR and authentication packets.
   1613    */
   1614   if((lcp_phase[pd] <= PHASE_AUTHENTICATE) && (protocol != PPP_LCP)) {
   1615     if(!((protocol == PPP_LQR) || (protocol == PPP_PAP) || (protocol == PPP_CHAP)) ||
   1616         (lcp_phase[pd] != PHASE_AUTHENTICATE)) {
   1617       PPPDEBUG(LOG_INFO, ("pppInput: discarding proto 0x%"X16_F" in phase %d\n", protocol, lcp_phase[pd]));
   1618       goto drop;
   1619     }
   1620   }
   1621 
   1622   switch(protocol) {
   1623     case PPP_VJC_COMP:      /* VJ compressed TCP */
   1624 #if PPPOS_SUPPORT && VJ_SUPPORT
   1625       PPPDEBUG(LOG_INFO, ("pppInput[%d]: vj_comp in pbuf len=%d\n", pd, nb->len));
   1626       /*
   1627        * Clip off the VJ header and prepend the rebuilt TCP/IP header and
   1628        * pass the result to IP.
   1629        */
   1630       if ((vj_uncompress_tcp(&nb, &pppControl[pd].vjComp) >= 0) && (pppControl[pd].netif.input)) {
   1631         pppControl[pd].netif.input(nb, &pppControl[pd].netif);
   1632         return;
   1633       }
   1634       /* Something's wrong so drop it. */
   1635       PPPDEBUG(LOG_WARNING, ("pppInput[%d]: Dropping VJ compressed\n", pd));
   1636 #else  /* PPPOS_SUPPORT && VJ_SUPPORT */
   1637       /* No handler for this protocol so drop the packet. */
   1638       PPPDEBUG(LOG_INFO, ("pppInput[%d]: drop VJ Comp in %d:%s\n", pd, nb->len, nb->payload));
   1639 #endif /* PPPOS_SUPPORT && VJ_SUPPORT */
   1640       break;
   1641 
   1642     case PPP_VJC_UNCOMP:    /* VJ uncompressed TCP */
   1643 #if PPPOS_SUPPORT && VJ_SUPPORT
   1644       PPPDEBUG(LOG_INFO, ("pppInput[%d]: vj_un in pbuf len=%d\n", pd, nb->len));
   1645       /*
   1646        * Process the TCP/IP header for VJ header compression and then pass
   1647        * the packet to IP.
   1648        */
   1649       if ((vj_uncompress_uncomp(nb, &pppControl[pd].vjComp) >= 0) && pppControl[pd].netif.input) {
   1650         pppControl[pd].netif.input(nb, &pppControl[pd].netif);
   1651         return;
   1652       }
   1653       /* Something's wrong so drop it. */
   1654       PPPDEBUG(LOG_WARNING, ("pppInput[%d]: Dropping VJ uncompressed\n", pd));
   1655 #else  /* PPPOS_SUPPORT && VJ_SUPPORT */
   1656       /* No handler for this protocol so drop the packet. */
   1657       PPPDEBUG(LOG_INFO,
   1658                ("pppInput[%d]: drop VJ UnComp in %d:.*H\n",
   1659                 pd, nb->len, LWIP_MIN(nb->len * 2, 40), nb->payload));
   1660 #endif /* PPPOS_SUPPORT && VJ_SUPPORT */
   1661       break;
   1662 
   1663     case PPP_IP:            /* Internet Protocol */
   1664       PPPDEBUG(LOG_INFO, ("pppInput[%d]: ip in pbuf len=%d\n", pd, nb->len));
   1665       if (pppControl[pd].netif.input) {
   1666         pppControl[pd].netif.input(nb, &pppControl[pd].netif);
   1667         return;
   1668       }
   1669       break;
   1670 
   1671     default: {
   1672       struct protent *protp;
   1673       int i;
   1674 
   1675       /*
   1676        * Upcall the proper protocol input routine.
   1677        */
   1678       for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) {
   1679         if (protp->protocol == protocol && protp->enabled_flag) {
   1680           PPPDEBUG(LOG_INFO, ("pppInput[%d]: %s len=%d\n", pd, protp->name, nb->len));
   1681           nb = pppSingleBuf(nb);
   1682           (*protp->input)(pd, nb->payload, nb->len);
   1683           PPPDEBUG(LOG_DETAIL, ("pppInput[%d]: packet processed\n", pd));
   1684           goto out;
   1685         }
   1686       }
   1687 
   1688       /* No handler for this protocol so reject the packet. */
   1689       PPPDEBUG(LOG_INFO, ("pppInput[%d]: rejecting unsupported proto 0x%"X16_F" len=%d\n", pd, protocol, nb->len));
   1690       if (pbuf_header(nb, sizeof(protocol))) {
   1691         LWIP_ASSERT("pbuf_header failed\n", 0);
   1692         goto drop;
   1693       }
   1694 #if BYTE_ORDER == LITTLE_ENDIAN
   1695       protocol = htons(protocol);
   1696 #endif /* BYTE_ORDER == LITTLE_ENDIAN */
   1697       SMEMCPY(nb->payload, &protocol, sizeof(protocol));
   1698       lcp_sprotrej(pd, nb->payload, nb->len);
   1699     }
   1700     break;
   1701   }
   1702 
   1703 drop:
   1704   LINK_STATS_INC(link.drop);
   1705   snmp_inc_ifindiscards(&pppControl[pd].netif);
   1706 
   1707 out:
   1708   pbuf_free(nb);
   1709   return;
   1710 }
   1711 
   1712 #if PPPOS_SUPPORT
   1713 /*
   1714  * Drop the input packet.
   1715  */
   1716 static void
   1717 pppDrop(PPPControlRx *pcrx)
   1718 {
   1719   if (pcrx->inHead != NULL) {
   1720 #if 0
   1721     PPPDEBUG(LOG_INFO, ("pppDrop: %d:%.*H\n", pcrx->inHead->len, min(60, pcrx->inHead->len * 2), pcrx->inHead->payload));
   1722 #endif
   1723     PPPDEBUG(LOG_INFO, ("pppDrop: pbuf len=%d, addr %p\n", pcrx->inHead->len, (void*)pcrx->inHead));
   1724     if (pcrx->inTail && (pcrx->inTail != pcrx->inHead)) {
   1725       pbuf_free(pcrx->inTail);
   1726     }
   1727     pbuf_free(pcrx->inHead);
   1728     pcrx->inHead = NULL;
   1729     pcrx->inTail = NULL;
   1730   }
   1731 #if VJ_SUPPORT
   1732   vj_uncompress_err(&pppControl[pcrx->pd].vjComp);
   1733 #endif /* VJ_SUPPORT */
   1734 
   1735   LINK_STATS_INC(link.drop);
   1736   snmp_inc_ifindiscards(&pppControl[pcrx->pd].netif);
   1737 }
   1738 
   1739 /** Pass received raw characters to PPPoS to be decoded. This function is
   1740  * thread-safe and can be called from a dedicated RX-thread or from a main-loop.
   1741  *
   1742  * @param pd PPP descriptor index, returned by pppOpen()
   1743  * @param data received data
   1744  * @param len length of received data
   1745  */
   1746 void
   1747 pppos_input(int pd, u_char* data, int len)
   1748 {
   1749   pppInProc(&pppControl[pd].rx, data, len);
   1750 }
   1751 
   1752 /**
   1753  * Process a received octet string.
   1754  */
   1755 static void
   1756 pppInProc(PPPControlRx *pcrx, u_char *s, int l)
   1757 {
   1758   struct pbuf *nextNBuf;
   1759   u_char curChar;
   1760   u_char escaped;
   1761   SYS_ARCH_DECL_PROTECT(lev);
   1762 
   1763   PPPDEBUG(LOG_DEBUG, ("pppInProc[%d]: got %d bytes\n", pcrx->pd, l));
   1764   while (l-- > 0) {
   1765     curChar = *s++;
   1766 
   1767     SYS_ARCH_PROTECT(lev);
   1768     escaped = ESCAPE_P(pcrx->inACCM, curChar);
   1769     SYS_ARCH_UNPROTECT(lev);
   1770     /* Handle special characters. */
   1771     if (escaped) {
   1772       /* Check for escape sequences. */
   1773       /* XXX Note that this does not handle an escaped 0x5d character which
   1774        * would appear as an escape character.  Since this is an ASCII ']'
   1775        * and there is no reason that I know of to escape it, I won't complicate
   1776        * the code to handle this case. GLL */
   1777       if (curChar == PPP_ESCAPE) {
   1778         pcrx->inEscaped = 1;
   1779       /* Check for the flag character. */
   1780       } else if (curChar == PPP_FLAG) {
   1781         /* If this is just an extra flag character, ignore it. */
   1782         if (pcrx->inState <= PDADDRESS) {
   1783           /* ignore it */;
   1784         /* If we haven't received the packet header, drop what has come in. */
   1785         } else if (pcrx->inState < PDDATA) {
   1786           PPPDEBUG(LOG_WARNING,
   1787                    ("pppInProc[%d]: Dropping incomplete packet %d\n",
   1788                     pcrx->pd, pcrx->inState));
   1789           LINK_STATS_INC(link.lenerr);
   1790           pppDrop(pcrx);
   1791         /* If the fcs is invalid, drop the packet. */
   1792         } else if (pcrx->inFCS != PPP_GOODFCS) {
   1793           PPPDEBUG(LOG_INFO,
   1794                    ("pppInProc[%d]: Dropping bad fcs 0x%"X16_F" proto=0x%"X16_F"\n",
   1795                     pcrx->pd, pcrx->inFCS, pcrx->inProtocol));
   1796           /* Note: If you get lots of these, check for UART frame errors or try different baud rate */
   1797           LINK_STATS_INC(link.chkerr);
   1798           pppDrop(pcrx);
   1799         /* Otherwise it's a good packet so pass it on. */
   1800         } else {
   1801           struct pbuf *inp;
   1802           /* Trim off the checksum. */
   1803           if(pcrx->inTail->len >= 2) {
   1804             pcrx->inTail->len -= 2;
   1805 
   1806             pcrx->inTail->tot_len = pcrx->inTail->len;
   1807             if (pcrx->inTail != pcrx->inHead) {
   1808               pbuf_cat(pcrx->inHead, pcrx->inTail);
   1809             }
   1810           } else {
   1811             pcrx->inTail->tot_len = pcrx->inTail->len;
   1812             if (pcrx->inTail != pcrx->inHead) {
   1813               pbuf_cat(pcrx->inHead, pcrx->inTail);
   1814             }
   1815 
   1816             pbuf_realloc(pcrx->inHead, pcrx->inHead->tot_len - 2);
   1817           }
   1818 
   1819           /* Dispatch the packet thereby consuming it. */
   1820           inp = pcrx->inHead;
   1821           /* Packet consumed, release our references. */
   1822           pcrx->inHead = NULL;
   1823           pcrx->inTail = NULL;
   1824 #if PPP_INPROC_MULTITHREADED
   1825           if(tcpip_callback_with_block(pppInput, inp, 0) != ERR_OK) {
   1826             PPPDEBUG(LOG_ERR, ("pppInProc[%d]: tcpip_callback() failed, dropping packet\n", pcrx->pd));
   1827             pbuf_free(inp);
   1828             LINK_STATS_INC(link.drop);
   1829             snmp_inc_ifindiscards(&pppControl[pcrx->pd].netif);
   1830           }
   1831 #else /* PPP_INPROC_MULTITHREADED */
   1832           pppInput(inp);
   1833 #endif /* PPP_INPROC_MULTITHREADED */
   1834         }
   1835 
   1836         /* Prepare for a new packet. */
   1837         pcrx->inFCS = PPP_INITFCS;
   1838         pcrx->inState = PDADDRESS;
   1839         pcrx->inEscaped = 0;
   1840       /* Other characters are usually control characters that may have
   1841        * been inserted by the physical layer so here we just drop them. */
   1842       } else {
   1843         PPPDEBUG(LOG_WARNING,
   1844                  ("pppInProc[%d]: Dropping ACCM char <%d>\n", pcrx->pd, curChar));
   1845       }
   1846     /* Process other characters. */
   1847     } else {
   1848       /* Unencode escaped characters. */
   1849       if (pcrx->inEscaped) {
   1850         pcrx->inEscaped = 0;
   1851         curChar ^= PPP_TRANS;
   1852       }
   1853 
   1854       /* Process character relative to current state. */
   1855       switch(pcrx->inState) {
   1856         case PDIDLE:                    /* Idle state - waiting. */
   1857           /* Drop the character if it's not 0xff
   1858            * we would have processed a flag character above. */
   1859           if (curChar != PPP_ALLSTATIONS) {
   1860             break;
   1861           }
   1862 
   1863         /* Fall through */
   1864         case PDSTART:                   /* Process start flag. */
   1865           /* Prepare for a new packet. */
   1866           pcrx->inFCS = PPP_INITFCS;
   1867 
   1868         /* Fall through */
   1869         case PDADDRESS:                 /* Process address field. */
   1870           if (curChar == PPP_ALLSTATIONS) {
   1871             pcrx->inState = PDCONTROL;
   1872             break;
   1873           }
   1874           /* Else assume compressed address and control fields so
   1875            * fall through to get the protocol... */
   1876         case PDCONTROL:                 /* Process control field. */
   1877           /* If we don't get a valid control code, restart. */
   1878           if (curChar == PPP_UI) {
   1879             pcrx->inState = PDPROTOCOL1;
   1880             break;
   1881           }
   1882 #if 0
   1883           else {
   1884             PPPDEBUG(LOG_WARNING,
   1885                      ("pppInProc[%d]: Invalid control <%d>\n", pcrx->pd, curChar));
   1886             pcrx->inState = PDSTART;
   1887           }
   1888 #endif
   1889         case PDPROTOCOL1:               /* Process protocol field 1. */
   1890           /* If the lower bit is set, this is the end of the protocol
   1891            * field. */
   1892           if (curChar & 1) {
   1893             pcrx->inProtocol = curChar;
   1894             pcrx->inState = PDDATA;
   1895           } else {
   1896             pcrx->inProtocol = (u_int)curChar << 8;
   1897             pcrx->inState = PDPROTOCOL2;
   1898           }
   1899           break;
   1900         case PDPROTOCOL2:               /* Process protocol field 2. */
   1901           pcrx->inProtocol |= curChar;
   1902           pcrx->inState = PDDATA;
   1903           break;
   1904         case PDDATA:                    /* Process data byte. */
   1905           /* Make space to receive processed data. */
   1906           if (pcrx->inTail == NULL || pcrx->inTail->len == PBUF_POOL_BUFSIZE) {
   1907             if (pcrx->inTail != NULL) {
   1908               pcrx->inTail->tot_len = pcrx->inTail->len;
   1909               if (pcrx->inTail != pcrx->inHead) {
   1910                 pbuf_cat(pcrx->inHead, pcrx->inTail);
   1911                 /* give up the inTail reference now */
   1912                 pcrx->inTail = NULL;
   1913               }
   1914             }
   1915             /* If we haven't started a packet, we need a packet header. */
   1916             nextNBuf = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
   1917             if (nextNBuf == NULL) {
   1918               /* No free buffers.  Drop the input packet and let the
   1919                * higher layers deal with it.  Continue processing
   1920                * the received pbuf chain in case a new packet starts. */
   1921               PPPDEBUG(LOG_ERR, ("pppInProc[%d]: NO FREE MBUFS!\n", pcrx->pd));
   1922               LINK_STATS_INC(link.memerr);
   1923               pppDrop(pcrx);
   1924               pcrx->inState = PDSTART;  /* Wait for flag sequence. */
   1925               break;
   1926             }
   1927             if (pcrx->inHead == NULL) {
   1928               struct pppInputHeader *pih = nextNBuf->payload;
   1929 
   1930               pih->unit = pcrx->pd;
   1931               pih->proto = pcrx->inProtocol;
   1932 
   1933               nextNBuf->len += sizeof(*pih);
   1934 
   1935               pcrx->inHead = nextNBuf;
   1936             }
   1937             pcrx->inTail = nextNBuf;
   1938           }
   1939           /* Load character into buffer. */
   1940           ((u_char*)pcrx->inTail->payload)[pcrx->inTail->len++] = curChar;
   1941           break;
   1942       }
   1943 
   1944       /* update the frame check sequence number. */
   1945       pcrx->inFCS = PPP_FCS(pcrx->inFCS, curChar);
   1946     }
   1947   } /* while (l-- > 0), all bytes processed */
   1948 
   1949   avRandomize();
   1950 }
   1951 #endif /* PPPOS_SUPPORT */
   1952 
   1953 #if PPPOE_SUPPORT
   1954 void
   1955 pppInProcOverEthernet(int pd, struct pbuf *pb)
   1956 {
   1957   struct pppInputHeader *pih;
   1958   u16_t inProtocol;
   1959 
   1960   if(pb->len < sizeof(inProtocol)) {
   1961     PPPDEBUG(LOG_ERR, ("pppInProcOverEthernet: too small for protocol field\n"));
   1962     goto drop;
   1963   }
   1964 
   1965   inProtocol = (((u8_t *)pb->payload)[0] << 8) | ((u8_t*)pb->payload)[1];
   1966 
   1967   /* make room for pppInputHeader - should not fail */
   1968   if (pbuf_header(pb, sizeof(*pih) - sizeof(inProtocol)) != 0) {
   1969     PPPDEBUG(LOG_ERR, ("pppInProcOverEthernet: could not allocate room for header\n"));
   1970     goto drop;
   1971   }
   1972 
   1973   pih = pb->payload;
   1974 
   1975   pih->unit = pd;
   1976   pih->proto = inProtocol;
   1977 
   1978   /* Dispatch the packet thereby consuming it. */
   1979   pppInput(pb);
   1980   return;
   1981 
   1982 drop:
   1983   LINK_STATS_INC(link.drop);
   1984   snmp_inc_ifindiscards(&pppControl[pd].netif);
   1985   pbuf_free(pb);
   1986   return;
   1987 }
   1988 #endif /* PPPOE_SUPPORT */
   1989 
   1990 #if LWIP_NETIF_STATUS_CALLBACK
   1991 /** Set the status callback of a PPP's netif
   1992  *
   1993  * @param pd The PPP descriptor returned by pppOpen()
   1994  * @param status_callback pointer to the status callback function
   1995  *
   1996  * @see netif_set_status_callback
   1997  */
   1998 void
   1999 ppp_set_netif_statuscallback(int pd, netif_status_callback_fn status_callback)
   2000 {
   2001   netif_set_status_callback(&pppControl[pd].netif, status_callback);
   2002 }
   2003 #endif /* LWIP_NETIF_STATUS_CALLBACK */
   2004 
   2005 #if LWIP_NETIF_LINK_CALLBACK
   2006 /** Set the link callback of a PPP's netif
   2007  *
   2008  * @param pd The PPP descriptor returned by pppOpen()
   2009  * @param link_callback pointer to the link callback function
   2010  *
   2011  * @see netif_set_link_callback
   2012  */
   2013 void
   2014 ppp_set_netif_linkcallback(int pd, netif_status_callback_fn link_callback)
   2015 {
   2016   netif_set_link_callback(&pppControl[pd].netif, link_callback);
   2017 }
   2018 #endif /* LWIP_NETIF_LINK_CALLBACK */
   2019 
   2020 #endif /* PPP_SUPPORT */
   2021