lwip_bleedingedge

Fork of lwip by mbed official

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ppp.c Source File

ppp.c

00001 /*****************************************************************************
00002 * ppp.c - Network Point to Point Protocol program file.
00003 *
00004 * Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
00005 * portions Copyright (c) 1997 by Global Election Systems Inc.
00006 *
00007 * The authors hereby grant permission to use, copy, modify, distribute,
00008 * and license this software and its documentation for any purpose, provided
00009 * that existing copyright notices are retained in all copies and that this
00010 * notice and the following disclaimer are included verbatim in any 
00011 * distributions. No written agreement, license, or royalty fee is required
00012 * for any of the authorized uses.
00013 *
00014 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
00015 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00016 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
00017 * IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00018 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00019 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00020 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00021 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00022 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00023 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00024 *
00025 ******************************************************************************
00026 * REVISION HISTORY
00027 *
00028 * 03-01-01 Marc Boucher <marc@mbsi.ca>
00029 *   Ported to lwIP.
00030 * 97-11-05 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
00031 *   Original.
00032 *****************************************************************************/
00033 
00034 /*
00035  * ppp_defs.h - PPP definitions.
00036  *
00037  * if_pppvar.h - private structures and declarations for PPP.
00038  *
00039  * Copyright (c) 1994 The Australian National University.
00040  * All rights reserved.
00041  *
00042  * Permission to use, copy, modify, and distribute this software and its
00043  * documentation is hereby granted, provided that the above copyright
00044  * notice appears in all copies.  This software is provided without any
00045  * warranty, express or implied. The Australian National University
00046  * makes no representations about the suitability of this software for
00047  * any purpose.
00048  *
00049  * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
00050  * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
00051  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
00052  * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
00053  * OF SUCH DAMAGE.
00054  *
00055  * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
00056  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
00057  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
00058  * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
00059  * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
00060  * OR MODIFICATIONS.
00061  */
00062 
00063 /*
00064  * if_ppp.h - Point-to-Point Protocol definitions.
00065  *
00066  * Copyright (c) 1989 Carnegie Mellon University.
00067  * All rights reserved.
00068  *
00069  * Redistribution and use in source and binary forms are permitted
00070  * provided that the above copyright notice and this paragraph are
00071  * duplicated in all such forms and that any documentation,
00072  * advertising materials, and other materials related to such
00073  * distribution and use acknowledge that the software was developed
00074  * by Carnegie Mellon University.  The name of the
00075  * University may not be used to endorse or promote products derived
00076  * from this software without specific prior written permission.
00077  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
00078  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
00079  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00080  */
00081 
00082 #include "lwip/opt.h"
00083 
00084 #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
00085 
00086 #include "lwip/ip.h" /* for ip_input() */
00087 
00088 #include "ppp.h"
00089 #include "pppdebug.h"
00090 
00091 #include "randm.h"
00092 #include "fsm.h"
00093 #if PAP_SUPPORT
00094 #include "pap.h"
00095 #endif /* PAP_SUPPORT */
00096 #if CHAP_SUPPORT
00097 #include "chap.h"
00098 #endif /* CHAP_SUPPORT */
00099 #include "ipcp.h"
00100 #include "lcp.h"
00101 #include "magic.h"
00102 #include "auth.h"
00103 #if VJ_SUPPORT
00104 #include "vj.h"
00105 #endif /* VJ_SUPPORT */
00106 #if PPPOE_SUPPORT
00107 #include "netif/ppp_oe.h"
00108 #endif /* PPPOE_SUPPORT */
00109 
00110 #include "lwip/tcpip.h"
00111 #include "lwip/api.h"
00112 #include "lwip/snmp.h"
00113 
00114 #include <string.h>
00115 
00116 /*************************/
00117 /*** LOCAL DEFINITIONS ***/
00118 /*************************/
00119 
00120 /** PPP_INPROC_MULTITHREADED==1 call pppInput using tcpip_callback().
00121  * Set this to 0 if pppInProc is called inside tcpip_thread or with NO_SYS==1.
00122  * Default is 1 for NO_SYS==0 (multithreaded) and 0 for NO_SYS==1 (single-threaded).
00123  */
00124 #ifndef PPP_INPROC_MULTITHREADED
00125 #define PPP_INPROC_MULTITHREADED (NO_SYS==0)
00126 #endif
00127 
00128 /** PPP_INPROC_OWNTHREAD==1: start a dedicated RX thread per PPP session.
00129  * Default is 0: call pppos_input() for received raw characters, charcater
00130  * reception is up to the port */
00131 #ifndef PPP_INPROC_OWNTHREAD
00132 #define PPP_INPROC_OWNTHREAD      PPP_INPROC_MULTITHREADED
00133 #endif
00134 
00135 #if PPP_INPROC_OWNTHREAD && !PPP_INPROC_MULTITHREADED
00136   #error "PPP_INPROC_OWNTHREAD needs PPP_INPROC_MULTITHREADED==1"
00137 #endif
00138 
00139 /*
00140  * The basic PPP frame.
00141  */
00142 #define PPP_ADDRESS(p)  (((u_char *)(p))[0])
00143 #define PPP_CONTROL(p)  (((u_char *)(p))[1])
00144 #define PPP_PROTOCOL(p) ((((u_char *)(p))[2] << 8) + ((u_char *)(p))[3])
00145 
00146 /* PPP packet parser states.  Current state indicates operation yet to be
00147  * completed. */
00148 typedef enum {
00149   PDIDLE = 0,  /* Idle state - waiting. */
00150   PDSTART,     /* Process start flag. */
00151   PDADDRESS,   /* Process address field. */
00152   PDCONTROL,   /* Process control field. */
00153   PDPROTOCOL1, /* Process protocol field 1. */
00154   PDPROTOCOL2, /* Process protocol field 2. */
00155   PDDATA       /* Process data byte. */
00156 } PPPDevStates;
00157 
00158 #define ESCAPE_P(accm, c) ((accm)[(c) >> 3] & pppACCMMask[c & 0x07])
00159 
00160 /************************/
00161 /*** LOCAL DATA TYPES ***/
00162 /************************/
00163 
00164 /** RX buffer size: this may be configured smaller! */
00165 #ifndef PPPOS_RX_BUFSIZE
00166 #define PPPOS_RX_BUFSIZE    (PPP_MRU + PPP_HDRLEN)
00167 #endif
00168 
00169 typedef struct PPPControlRx_s {
00170   /** unit number / ppp descriptor */
00171   int pd;
00172   /** the rx file descriptor */
00173   sio_fd_t fd;
00174   /** receive buffer - encoded data is stored here */
00175   u_char rxbuf[PPPOS_RX_BUFSIZE];
00176 
00177   /* The input packet. */
00178   struct pbuf *inHead, *inTail;
00179 
00180 #if PPPOS_SUPPORT
00181   u16_t inProtocol;             /* The input protocol code. */
00182   u16_t inFCS;                  /* Input Frame Check Sequence value. */
00183 #endif /* PPPOS_SUPPORT */
00184   PPPDevStates inState;         /* The input process state. */
00185   char inEscaped;               /* Escape next character. */
00186   ext_accm inACCM;              /* Async-Ctl-Char-Map for input. */
00187 } PPPControlRx;
00188 
00189 /*
00190  * PPP interface control block.
00191  */
00192 typedef struct PPPControl_s {
00193   PPPControlRx rx;
00194   char openFlag;                /* True when in use. */
00195 #if PPPOE_SUPPORT
00196   struct netif *ethif;
00197   struct pppoe_softc *pppoe_sc;
00198 #endif /* PPPOE_SUPPORT */
00199   int  if_up;                   /* True when the interface is up. */
00200   int  errCode;                 /* Code indicating why interface is down. */
00201 #if PPPOS_SUPPORT
00202   sio_fd_t fd;                  /* File device ID of port. */
00203 #endif /* PPPOS_SUPPORT */
00204   u16_t mtu;                    /* Peer's mru */
00205   int  pcomp;                   /* Does peer accept protocol compression? */
00206   int  accomp;                  /* Does peer accept addr/ctl compression? */
00207   u_long lastXMit;              /* Time of last transmission. */
00208   ext_accm outACCM;             /* Async-Ctl-Char-Map for output. */
00209 #if PPPOS_SUPPORT && VJ_SUPPORT
00210   int  vjEnabled;               /* Flag indicating VJ compression enabled. */
00211   struct vjcompress vjComp;     /* Van Jacobson compression header. */
00212 #endif /* PPPOS_SUPPORT && VJ_SUPPORT */
00213 
00214   struct netif netif;
00215 
00216   struct ppp_addrs addrs;
00217 
00218   void (*linkStatusCB)(void *ctx, int errCode, void *arg);
00219   void *linkStatusCtx;
00220 
00221 } PPPControl;
00222 
00223 
00224 /*
00225  * Ioctl definitions.
00226  */
00227 
00228 struct npioctl {
00229   int         protocol; /* PPP procotol, e.g. PPP_IP */
00230   enum NPmode mode;
00231 };
00232 
00233 
00234 
00235 /***********************************/
00236 /*** LOCAL FUNCTION DECLARATIONS ***/
00237 /***********************************/
00238 #if PPPOS_SUPPORT
00239 #if PPP_INPROC_OWNTHREAD
00240 static void pppInputThread(void *arg);
00241 #endif /* PPP_INPROC_OWNTHREAD */
00242 static void pppDrop(PPPControlRx *pcrx);
00243 static void pppInProc(PPPControlRx *pcrx, u_char *s, int l);
00244 static void pppFreeCurrentInputPacket(PPPControlRx *pcrx); //lwip 1.4.1 backport
00245 #endif /* PPPOS_SUPPORT */
00246 
00247 
00248 /******************************/
00249 /*** PUBLIC DATA STRUCTURES ***/
00250 /******************************/
00251 u_long subnetMask;
00252 
00253 static PPPControl pppControl[NUM_PPP] __attribute((section("AHBSRAM1"))); /* The PPP interface control blocks. */
00254 
00255 static sys_mutex_t pppMtx; //Used to prevent concurrent access from user thread (pppStop) and input thread (pppInproc)
00256 static sys_mbox_t pppMboxStart; //Used to signal PPP thread that a PPP session begins
00257 static sys_mbox_t pppMboxStopped; //Used to signal remote thread that a PPP session has stopped
00258 
00259 /*
00260  * PPP Data Link Layer "protocol" table.
00261  * One entry per supported protocol.
00262  * The last entry must be NULL.
00263  */
00264 struct protent *ppp_protocols[] = {
00265   &lcp_protent,
00266 #if PAP_SUPPORT
00267   &pap_protent,
00268 #endif /* PAP_SUPPORT */
00269 #if CHAP_SUPPORT
00270   &chap_protent,
00271 #endif /* CHAP_SUPPORT */
00272 #if CBCP_SUPPORT
00273   &cbcp_protent,
00274 #endif /* CBCP_SUPPORT */
00275   &ipcp_protent,
00276 #if CCP_SUPPORT
00277   &ccp_protent,
00278 #endif /* CCP_SUPPORT */
00279   NULL
00280 };
00281 
00282 
00283 /*
00284  * Buffers for outgoing packets.  This must be accessed only from the appropriate
00285  * PPP task so that it doesn't need to be protected to avoid collisions.
00286  */
00287 u_char outpacket_buf[NUM_PPP][PPP_MRU+PPP_HDRLEN] __attribute((section("AHBSRAM1")));
00288 
00289 
00290 /*****************************/
00291 /*** LOCAL DATA STRUCTURES ***/
00292 /*****************************/
00293 
00294 #if PPPOS_SUPPORT
00295 /*
00296  * FCS lookup table as calculated by genfcstab.
00297  * @todo: smaller, slower implementation for lower memory footprint?
00298  */
00299 static const u_short fcstab[256] = {
00300   0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
00301   0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
00302   0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
00303   0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
00304   0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
00305   0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
00306   0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
00307   0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
00308   0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
00309   0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
00310   0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
00311   0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
00312   0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
00313   0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
00314   0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
00315   0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
00316   0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
00317   0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
00318   0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
00319   0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
00320   0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
00321   0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
00322   0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
00323   0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
00324   0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
00325   0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
00326   0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
00327   0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
00328   0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
00329   0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
00330   0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
00331   0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
00332 };
00333 
00334 /* PPP's Asynchronous-Control-Character-Map.  The mask array is used
00335  * to select the specific bit for a character. */
00336 static u_char pppACCMMask[] = {
00337   0x01,
00338   0x02,
00339   0x04,
00340   0x08,
00341   0x10,
00342   0x20,
00343   0x40,
00344   0x80
00345 };
00346 
00347 /** Wake up the task blocked in reading from serial line (if any) */
00348 static void
00349 pppRecvWakeup(int pd)
00350 {
00351   PPPDEBUG(LOG_DEBUG, ("pppRecvWakeup: unit %d\n", pd));
00352   if (pppControl[pd].openFlag != 0) {
00353     sio_read_abort(pppControl[pd].fd);
00354   }
00355 }
00356 #endif /* PPPOS_SUPPORT */
00357 
00358 void
00359 pppLinkTerminated(int pd)
00360 {
00361   PPPDEBUG(LOG_DEBUG, ("pppLinkTerminated: unit %d\n", pd));
00362 
00363 #if PPPOE_SUPPORT
00364   if (pppControl[pd].ethif) {
00365     pppoe_disconnect(pppControl[pd].pppoe_sc);
00366   } else
00367 #endif /* PPPOE_SUPPORT */
00368   {
00369 #if PPPOS_SUPPORT
00370     PPPControl* pc;
00371     pppRecvWakeup(pd);
00372     pc = &pppControl[pd];
00373 
00374     PPPDEBUG(LOG_DEBUG, ("pppLinkTerminated: unit %d: linkStatusCB=%p errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));
00375     if (pc->linkStatusCB) {
00376       pc->linkStatusCB(pc->linkStatusCtx, pc->errCode ? pc->errCode : PPPERR_PROTOCOL, NULL);
00377     }
00378 
00379     pc->openFlag = 0;
00380 #endif /* PPPOS_SUPPORT */
00381   }
00382   PPPDEBUG(LOG_DEBUG, ("pppLinkTerminated: finished.\n"));
00383 }
00384 
00385 void
00386 pppLinkDown(int pd)
00387 {
00388   PPPDEBUG(LOG_DEBUG, ("pppLinkDown: unit %d\n", pd));
00389 
00390 #if PPPOE_SUPPORT
00391   if (pppControl[pd].ethif) {
00392     pppoe_disconnect(pppControl[pd].pppoe_sc);
00393   } else
00394 #endif /* PPPOE_SUPPORT */
00395   {
00396 #if PPPOS_SUPPORT
00397     pppRecvWakeup(pd);
00398 #endif /* PPPOS_SUPPORT */
00399   }
00400 }
00401 
00402 /** Initiate LCP open request */
00403 static void
00404 pppStart(int pd)
00405 {
00406   struct protent *protp;
00407   int j;
00408   /* Initialize each protocol to the standard option set. */
00409   for (j = 0; (protp = ppp_protocols[j]) != NULL; ++j) {
00410     (*protp->init)(pd);
00411   }
00412   PPPDEBUG(LOG_DEBUG, ("pppStart: unit %d\n", pd));
00413   lcp_lowerup(pd);
00414   lcp_open(pd); /* Start protocol */
00415   PPPDEBUG(LOG_DEBUG, ("pppStart: finished\n"));
00416 }
00417 
00418 /** LCP close request */
00419 static void
00420 pppStop(int pd)
00421 {
00422   PPPDEBUG(LOG_DEBUG, ("pppStop: unit %d\n", pd));
00423   lcp_close(pd, "User request");
00424 }
00425 
00426 /** Called when carrier/link is lost */
00427 static void
00428 pppHup(int pd)
00429 {
00430   PPPDEBUG(LOG_DEBUG, ("pppHupCB: unit %d\n", pd));
00431   lcp_lowerdown(pd);
00432   link_terminated(pd);
00433 }
00434 
00435 /***********************************/
00436 /*** PUBLIC FUNCTION DEFINITIONS ***/
00437 /***********************************/
00438 /* Initialize the PPP subsystem. */
00439 
00440 struct ppp_settings ppp_settings;
00441 
00442 void
00443 pppInit(void)
00444 {
00445   memset(&ppp_settings, 0, sizeof(ppp_settings));
00446   ppp_settings.usepeerdns = 1;
00447   pppSetAuth(PPPAUTHTYPE_NONE, NULL, NULL);
00448 
00449   magicInit();
00450 
00451   subnetMask = PP_HTONL(0xffffff00UL);
00452 
00453   sys_mutex_new(&pppMtx);
00454   sys_mbox_new(&pppMboxStart, 1);
00455   sys_mbox_new(&pppMboxStopped, 1);
00456   
00457   sys_thread_new(PPP_THREAD_NAME, pppInputThread, (void*)NULL, PPP_THREAD_STACKSIZE, PPP_THREAD_PRIO); //Create PPP thread here
00458 }
00459 
00460 void
00461 pppSetAuth(enum pppAuthType authType, const char *user, const char *passwd)
00462 {
00463   switch(authType) {
00464     case PPPAUTHTYPE_NONE:
00465     default:
00466 #ifdef LWIP_PPP_STRICT_PAP_REJECT
00467       ppp_settings.refuse_pap = 1;
00468 #else  /* LWIP_PPP_STRICT_PAP_REJECT */
00469       /* some providers request pap and accept an empty login/pw */
00470       ppp_settings.refuse_pap = 0;
00471 #endif /* LWIP_PPP_STRICT_PAP_REJECT */
00472       ppp_settings.refuse_chap = 1;
00473       break;
00474 
00475     case PPPAUTHTYPE_ANY:
00476       /* Warning: Using PPPAUTHTYPE_ANY might have security consequences.
00477        * RFC 1994 says:
00478        *
00479        * In practice, within or associated with each PPP server, there is a
00480        * database which associates "user" names with authentication
00481        * information ("secrets").  It is not anticipated that a particular
00482        * named user would be authenticated by multiple methods.  This would
00483        * make the user vulnerable to attacks which negotiate the least secure
00484        * method from among a set (such as PAP rather than CHAP).  If the same
00485        * secret was used, PAP would reveal the secret to be used later with
00486        * CHAP.
00487        *
00488        * Instead, for each user name there should be an indication of exactly
00489        * one method used to authenticate that user name.  If a user needs to
00490        * make use of different authentication methods under different
00491        * circumstances, then distinct user names SHOULD be employed, each of
00492        * which identifies exactly one authentication method.
00493        *
00494        */
00495       ppp_settings.refuse_pap = 0;
00496       ppp_settings.refuse_chap = 0;
00497       break;
00498 
00499     case PPPAUTHTYPE_PAP:
00500       ppp_settings.refuse_pap = 0;
00501       ppp_settings.refuse_chap = 1;
00502       break;
00503 
00504     case PPPAUTHTYPE_CHAP:
00505       ppp_settings.refuse_pap = 1;
00506       ppp_settings.refuse_chap = 0;
00507       break;
00508   }
00509 
00510   if(user) {
00511     strncpy(ppp_settings.user, user, sizeof(ppp_settings.user)-1);
00512     ppp_settings.user[sizeof(ppp_settings.user)-1] = '\0';
00513   } else {
00514     ppp_settings.user[0] = '\0';
00515   }
00516 
00517   if(passwd) {
00518     strncpy(ppp_settings.passwd, passwd, sizeof(ppp_settings.passwd)-1);
00519     ppp_settings.passwd[sizeof(ppp_settings.passwd)-1] = '\0';
00520   } else {
00521     ppp_settings.passwd[0] = '\0';
00522   }
00523 }
00524 
00525 #if PPPOS_SUPPORT
00526 /** Open a new PPP connection using the given I/O device.
00527  * This initializes the PPP control block but does not
00528  * attempt to negotiate the LCP session.  If this port
00529  * connects to a modem, the modem connection must be
00530  * established before calling this.
00531  * Return a new PPP connection descriptor on success or
00532  * an error code (negative) on failure.
00533  *
00534  * pppOpen() is directly defined to this function.
00535  */
00536 int
00537 pppOverSerialOpen(sio_fd_t fd, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx)
00538 {
00539   PPPControl *pc;
00540   int pd;
00541 
00542   if (linkStatusCB == NULL) {
00543     /* PPP is single-threaded: without a callback,
00544      * there is no way to know when the link is up. */
00545     return PPPERR_PARAM;
00546   }
00547 
00548   /* Find a free PPP session descriptor. */
00549   for (pd = 0; pd < NUM_PPP && pppControl[pd].openFlag != 0; pd++);
00550 
00551   if (pd >= NUM_PPP) {
00552     pd = PPPERR_OPEN;
00553   } else {
00554     pc = &pppControl[pd];
00555     /* input pbuf left over from last session? */ //Backport from lwip 1.4.1
00556     pppFreeCurrentInputPacket(&pc->rx);
00557     /* @todo: is this correct or do I overwrite something? */
00558     memset(pc, 0, sizeof(PPPControl));
00559     pc->rx.pd = pd;
00560     pc->rx.fd = fd;
00561 
00562     pc->openFlag = 1;
00563     pc->fd = fd;
00564 
00565 #if VJ_SUPPORT
00566     vj_compress_init(&pc->vjComp);
00567 #endif /* VJ_SUPPORT */
00568 
00569     /* 
00570      * Default the in and out accm so that escape and flag characters
00571      * are always escaped. 
00572      */
00573     pc->rx.inACCM[15] = 0x60; /* no need to protect since RX is not running */
00574     pc->outACCM[15] = 0x60;
00575 
00576     pc->linkStatusCB = linkStatusCB;
00577     pc->linkStatusCtx = linkStatusCtx;
00578 
00579     /*
00580      * Start the connection and handle incoming events (packet or timeout).
00581      */
00582     PPPDEBUG(LOG_INFO, ("pppOverSerialOpen: unit %d: Connecting\n", pd));
00583     pppStart(pd);
00584 #if PPP_INPROC_OWNTHREAD
00585     sys_mbox_post(&pppMboxStart, (void*)&pc->rx);
00586 #endif
00587   }
00588 
00589   return pd;
00590 }
00591 #endif /* PPPOS_SUPPORT */
00592 
00593 #if PPPOE_SUPPORT
00594 static void pppOverEthernetLinkStatusCB(int pd, int up);
00595 
00596 void
00597 pppOverEthernetClose(int pd)
00598 {
00599   PPPControl* pc = &pppControl[pd];
00600 
00601   /* *TJL* There's no lcp_deinit */
00602   lcp_close(pd, NULL);
00603 
00604   pppoe_destroy(&pc->netif);
00605 }
00606 
00607 int pppOverEthernetOpen(struct netif *ethif, const char *service_name, const char *concentrator_name, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx)
00608 {
00609   PPPControl *pc;
00610   int pd;
00611 
00612   LWIP_UNUSED_ARG(service_name);
00613   LWIP_UNUSED_ARG(concentrator_name);
00614 
00615   if (linkStatusCB == NULL) {
00616     /* PPP is single-threaded: without a callback,
00617      * there is no way to know when the link is up. */
00618     return PPPERR_PARAM;
00619   }
00620 
00621   /* Find a free PPP session descriptor. Critical region? */
00622   for (pd = 0; pd < NUM_PPP && pppControl[pd].openFlag != 0; pd++);
00623   if (pd >= NUM_PPP) {
00624     pd = PPPERR_OPEN;
00625   } else {
00626     pc = &pppControl[pd];
00627     memset(pc, 0, sizeof(PPPControl));
00628     pc->openFlag = 1;
00629     pc->ethif = ethif;
00630 
00631     pc->linkStatusCB  = linkStatusCB;
00632     pc->linkStatusCtx = linkStatusCtx;
00633 
00634     lcp_wantoptions[pd].mru = PPPOE_MAXMTU;
00635     lcp_wantoptions[pd].neg_asyncmap = 0;
00636     lcp_wantoptions[pd].neg_pcompression = 0;
00637     lcp_wantoptions[pd].neg_accompression = 0;
00638 
00639     lcp_allowoptions[pd].mru = PPPOE_MAXMTU;
00640     lcp_allowoptions[pd].neg_asyncmap = 0;
00641     lcp_allowoptions[pd].neg_pcompression = 0;
00642     lcp_allowoptions[pd].neg_accompression = 0;
00643 
00644     if(pppoe_create(ethif, pd, pppOverEthernetLinkStatusCB, &pc->pppoe_sc) != ERR_OK) {
00645       pc->openFlag = 0;
00646       return PPPERR_OPEN;
00647     }
00648 
00649     pppoe_connect(pc->pppoe_sc);
00650   }
00651 
00652   return pd;
00653 }
00654 #endif /* PPPOE_SUPPORT */
00655 
00656 
00657 /* Close a PPP connection and release the descriptor. 
00658  * Any outstanding packets in the queues are dropped.
00659  * Return 0 on success, an error code on failure. */
00660 int
00661 pppClose(int pd)
00662 {
00663   PPPControl *pc = &pppControl[pd];
00664   int st = 0;
00665 
00666   PPPDEBUG(LOG_DEBUG, ("pppClose() called\n"));
00667   
00668   sys_mutex_lock(&pppMtx);
00669   
00670   /* Disconnect */
00671 #if PPPOE_SUPPORT
00672   if(pc->ethif) {
00673     PPPDEBUG(LOG_DEBUG, ("pppClose: unit %d kill_link -> pppStop\n", pd));
00674     pc->errCode = PPPERR_USER;
00675     /* This will leave us at PHASE_DEAD. */
00676     pppStop(pd);
00677   } else
00678 #endif /* PPPOE_SUPPORT */
00679   {
00680 #if PPPOS_SUPPORT
00681     PPPDEBUG(LOG_DEBUG, ("pppClose: unit %d kill_link -> pppStop\n", pd));
00682     pc->errCode = PPPERR_USER;
00683     /* This will leave us at PHASE_DEAD. */
00684     pppStop(pd);
00685     pppRecvWakeup(pd);
00686 #endif /* PPPOS_SUPPORT */
00687   }
00688   
00689   sys_mutex_unlock(&pppMtx);
00690 
00691   void* pcrx;
00692   sys_arch_mbox_fetch(&pppMboxStopped, (void**)&pcrx, 0); //Wait indefinitely for link to become dead
00693 
00694   return st;
00695 }
00696 
00697 /* This function is called when carrier is lost on the PPP channel. */
00698 void
00699 pppSigHUP(int pd)
00700 {
00701   PPPDEBUG(LOG_DEBUG, ("pppSigHUP: unit %d sig_hup -> pppHupCB\n", pd));
00702   pppHup(pd);
00703 }
00704 
00705 #if PPPOS_SUPPORT
00706 static void
00707 nPut(PPPControl *pc, struct pbuf *nb)
00708 {
00709   struct pbuf *b;
00710   int c;
00711 
00712   for(b = nb; b != NULL; b = b->next) {
00713     if((c = sio_write(pc->fd, b->payload, b->len)) != b->len) {
00714       PPPDEBUG(LOG_WARNING,
00715                ("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));
00716       LINK_STATS_INC(link.err);
00717       pc->lastXMit = 0; /* prepend PPP_FLAG to next packet */
00718       snmp_inc_ifoutdiscards(&pc->netif);
00719       pbuf_free(nb);
00720       return;
00721     }
00722   }
00723 
00724   snmp_add_ifoutoctets(&pc->netif, nb->tot_len);
00725   snmp_inc_ifoutucastpkts(&pc->netif);
00726   pbuf_free(nb);
00727   LINK_STATS_INC(link.xmit);
00728 }
00729 
00730 /* 
00731  * pppAppend - append given character to end of given pbuf.  If outACCM
00732  * is not NULL and the character needs to be escaped, do so.
00733  * If pbuf is full, append another.
00734  * Return the current pbuf.
00735  */
00736 static struct pbuf *
00737 pppAppend(u_char c, struct pbuf *nb, ext_accm *outACCM)
00738 {
00739   struct pbuf *tb = nb;
00740   
00741   /* Make sure there is room for the character and an escape code.
00742    * Sure we don't quite fill the buffer if the character doesn't
00743    * get escaped but is one character worth complicating this? */
00744   /* Note: We assume no packet header. */
00745   if (nb && (PBUF_POOL_BUFSIZE - nb->len) < 2) {
00746     tb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
00747     if (tb) {
00748       nb->next = tb;
00749     } else {
00750       LINK_STATS_INC(link.memerr);
00751     }
00752     nb = tb;
00753   }
00754 
00755   if (nb) {
00756     if (outACCM && ESCAPE_P(*outACCM, c)) {
00757       *((u_char*)nb->payload + nb->len++) = PPP_ESCAPE;
00758       *((u_char*)nb->payload + nb->len++) = c ^ PPP_TRANS;
00759     } else {
00760       *((u_char*)nb->payload + nb->len++) = c;
00761     }
00762   }
00763 
00764   return tb;
00765 }
00766 #endif /* PPPOS_SUPPORT */
00767 
00768 #if PPPOE_SUPPORT
00769 static err_t
00770 pppifOutputOverEthernet(int pd, struct pbuf *p)
00771 {
00772   PPPControl *pc = &pppControl[pd];
00773   struct pbuf *pb;
00774   u_short protocol = PPP_IP;
00775   int i=0;
00776   u16_t tot_len;
00777 
00778   /* @todo: try to use pbuf_header() here! */
00779   pb = pbuf_alloc(PBUF_LINK, PPPOE_HDRLEN + sizeof(protocol), PBUF_RAM);
00780   if(!pb) {
00781     LINK_STATS_INC(link.memerr);
00782     LINK_STATS_INC(link.proterr);
00783     snmp_inc_ifoutdiscards(&pc->netif);
00784     return ERR_MEM;
00785   }
00786 
00787   pbuf_header(pb, -(s16_t)PPPOE_HDRLEN);
00788 
00789   pc->lastXMit = sys_jiffies();
00790 
00791   if (!pc->pcomp || protocol > 0xFF) {
00792     *((u_char*)pb->payload + i++) = (protocol >> 8) & 0xFF;
00793   }
00794   *((u_char*)pb->payload + i) = protocol & 0xFF;
00795 
00796   pbuf_chain(pb, p);
00797   tot_len = pb->tot_len;
00798 
00799   if(pppoe_xmit(pc->pppoe_sc, pb) != ERR_OK) {
00800     LINK_STATS_INC(link.err);
00801     snmp_inc_ifoutdiscards(&pc->netif);
00802     return PPPERR_DEVICE;
00803   }
00804 
00805   snmp_add_ifoutoctets(&pc->netif, tot_len);
00806   snmp_inc_ifoutucastpkts(&pc->netif);
00807   LINK_STATS_INC(link.xmit);
00808   return ERR_OK;
00809 }
00810 #endif /* PPPOE_SUPPORT */
00811 
00812 /* Send a packet on the given connection. */
00813 static err_t
00814 pppifOutput(struct netif *netif, struct pbuf *pb, ip_addr_t *ipaddr)
00815 {
00816   int pd = (int)(size_t)netif->state;
00817   PPPControl *pc = &pppControl[pd];
00818 #if PPPOS_SUPPORT
00819   u_short protocol = PPP_IP;
00820   u_int fcsOut = PPP_INITFCS;
00821   struct pbuf *headMB = NULL, *tailMB = NULL, *p;
00822   u_char c;
00823 #endif /* PPPOS_SUPPORT */
00824 
00825   LWIP_UNUSED_ARG(ipaddr);
00826 
00827   /* Validate parameters. */
00828   /* We let any protocol value go through - it can't hurt us
00829    * and the peer will just drop it if it's not accepting it. */
00830   if (pd < 0 || pd >= NUM_PPP || !pc->openFlag || !pb) {
00831     PPPDEBUG(LOG_WARNING, ("pppifOutput[%d]: bad parms prot=%d pb=%p\n",
00832               pd, PPP_IP, pb));
00833     LINK_STATS_INC(link.opterr);
00834     LINK_STATS_INC(link.drop);
00835     snmp_inc_ifoutdiscards(netif);
00836     return ERR_ARG;
00837   }
00838 
00839   /* Check that the link is up. */
00840   if (lcp_phase[pd] == PHASE_DEAD) {
00841     PPPDEBUG(LOG_ERR, ("pppifOutput[%d]: link not up\n", pd));
00842     LINK_STATS_INC(link.rterr);
00843     LINK_STATS_INC(link.drop);
00844     snmp_inc_ifoutdiscards(netif);
00845     return ERR_RTE;
00846   }
00847 
00848 #if PPPOE_SUPPORT
00849   if(pc->ethif) {
00850     return pppifOutputOverEthernet(pd, pb);
00851   }
00852 #endif /* PPPOE_SUPPORT */
00853 
00854 #if PPPOS_SUPPORT
00855   /* Grab an output buffer. */
00856   headMB = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
00857   if (headMB == NULL) {
00858     PPPDEBUG(LOG_WARNING, ("pppifOutput[%d]: first alloc fail\n", pd));
00859     LINK_STATS_INC(link.memerr);
00860     LINK_STATS_INC(link.drop);
00861     snmp_inc_ifoutdiscards(netif);
00862     return ERR_MEM;
00863   }
00864 
00865 #if VJ_SUPPORT
00866   /* 
00867    * Attempt Van Jacobson header compression if VJ is configured and
00868    * this is an IP packet. 
00869    */
00870   if (protocol == PPP_IP && pc->vjEnabled) {
00871     switch (vj_compress_tcp(&pc->vjComp, pb)) {
00872       case TYPE_IP:
00873         /* No change...
00874            protocol = PPP_IP_PROTOCOL; */
00875         break;
00876       case TYPE_COMPRESSED_TCP:
00877         protocol = PPP_VJC_COMP;
00878         break;
00879       case TYPE_UNCOMPRESSED_TCP:
00880         protocol = PPP_VJC_UNCOMP;
00881         break;
00882       default:
00883         PPPDEBUG(LOG_WARNING, ("pppifOutput[%d]: bad IP packet\n", pd));
00884         LINK_STATS_INC(link.proterr);
00885         LINK_STATS_INC(link.drop);
00886         snmp_inc_ifoutdiscards(netif);
00887         pbuf_free(headMB);
00888         return ERR_VAL;
00889     }
00890   }
00891 #endif /* VJ_SUPPORT */
00892 
00893   tailMB = headMB;
00894 
00895   /* Build the PPP header. */
00896   if ((sys_jiffies() - pc->lastXMit) >= PPP_MAXIDLEFLAG) {
00897     tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
00898   }
00899 
00900   pc->lastXMit = sys_jiffies();
00901   if (!pc->accomp) {
00902     fcsOut = PPP_FCS(fcsOut, PPP_ALLSTATIONS);
00903     tailMB = pppAppend(PPP_ALLSTATIONS, tailMB, &pc->outACCM);
00904     fcsOut = PPP_FCS(fcsOut, PPP_UI);
00905     tailMB = pppAppend(PPP_UI, tailMB, &pc->outACCM);
00906   }
00907   if (!pc->pcomp || protocol > 0xFF) {
00908     c = (protocol >> 8) & 0xFF;
00909     fcsOut = PPP_FCS(fcsOut, c);
00910     tailMB = pppAppend(c, tailMB, &pc->outACCM);
00911   }
00912   c = protocol & 0xFF;
00913   fcsOut = PPP_FCS(fcsOut, c);
00914   tailMB = pppAppend(c, tailMB, &pc->outACCM);
00915 
00916   /* Load packet. */
00917   for(p = pb; p; p = p->next) {
00918     int n;
00919     u_char *sPtr;
00920 
00921     sPtr = (u_char*)p->payload;
00922     n = p->len;
00923     while (n-- > 0) {
00924       c = *sPtr++;
00925 
00926       /* Update FCS before checking for special characters. */
00927       fcsOut = PPP_FCS(fcsOut, c);
00928       
00929       /* Copy to output buffer escaping special characters. */
00930       tailMB = pppAppend(c, tailMB, &pc->outACCM);
00931     }
00932   }
00933 
00934   /* Add FCS and trailing flag. */
00935   c = ~fcsOut & 0xFF;
00936   tailMB = pppAppend(c, tailMB, &pc->outACCM);
00937   c = (~fcsOut >> 8) & 0xFF;
00938   tailMB = pppAppend(c, tailMB, &pc->outACCM);
00939   tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
00940 
00941   /* If we failed to complete the packet, throw it away. */
00942   if (!tailMB) {
00943     PPPDEBUG(LOG_WARNING,
00944              ("pppifOutput[%d]: Alloc err - dropping proto=%d\n", 
00945               pd, protocol));
00946     pbuf_free(headMB);
00947     LINK_STATS_INC(link.memerr);
00948     LINK_STATS_INC(link.drop);
00949     snmp_inc_ifoutdiscards(netif);
00950     return ERR_MEM;
00951   }
00952 
00953   /* Send it. */
00954   PPPDEBUG(LOG_INFO, ("pppifOutput[%d]: proto=0x%"X16_F"\n", pd, protocol));
00955 
00956   nPut(pc, headMB);
00957 #endif /* PPPOS_SUPPORT */
00958 
00959   return ERR_OK;
00960 }
00961 
00962 /* Get and set parameters for the given connection.
00963  * Return 0 on success, an error code on failure. */
00964 int
00965 pppIOCtl(int pd, int cmd, void *arg)
00966 {
00967   PPPControl *pc = &pppControl[pd];
00968   int st = 0;
00969 
00970   if (pd < 0 || pd >= NUM_PPP) {
00971     st = PPPERR_PARAM;
00972   } else {
00973     switch(cmd) {
00974     case PPPCTLG_UPSTATUS:      /* Get the PPP up status. */
00975       if (arg) {
00976         *(int *)arg = (int)(pc->if_up);
00977       } else {
00978         st = PPPERR_PARAM;
00979       }
00980       break;
00981     case PPPCTLS_ERRCODE:       /* Set the PPP error code. */
00982       if (arg) {
00983         pc->errCode = *(int *)arg;
00984       } else {
00985         st = PPPERR_PARAM;
00986       }
00987       break;
00988     case PPPCTLG_ERRCODE:       /* Get the PPP error code. */
00989       if (arg) {
00990         *(int *)arg = (int)(pc->errCode);
00991       } else {
00992         st = PPPERR_PARAM;
00993       }
00994       break;
00995 #if PPPOS_SUPPORT
00996     case PPPCTLG_FD:            /* Get the fd associated with the ppp */
00997       if (arg) {
00998         *(sio_fd_t *)arg = pc->fd;
00999       } else {
01000         st = PPPERR_PARAM;
01001       }
01002       break;
01003 #endif /* PPPOS_SUPPORT */
01004     default:
01005       st = PPPERR_PARAM;
01006       break;
01007     }
01008   }
01009 
01010   return st;
01011 }
01012 
01013 /*
01014  * Return the Maximum Transmission Unit for the given PPP connection.
01015  */
01016 u_short
01017 pppMTU(int pd)
01018 {
01019   PPPControl *pc = &pppControl[pd];
01020   u_short st;
01021 
01022   /* Validate parameters. */
01023   if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
01024     st = 0;
01025   } else {
01026     st = pc->mtu;
01027   }
01028 
01029   return st;
01030 }
01031 
01032 #if PPPOE_SUPPORT
01033 int
01034 pppWriteOverEthernet(int pd, const u_char *s, int n)
01035 {
01036   PPPControl *pc = &pppControl[pd];
01037   struct pbuf *pb;
01038 
01039   /* skip address & flags */
01040   s += 2;
01041   n -= 2;
01042 
01043   LWIP_ASSERT("PPPOE_HDRLEN + n <= 0xffff", PPPOE_HDRLEN + n <= 0xffff);
01044   pb = pbuf_alloc(PBUF_LINK, (u16_t)(PPPOE_HDRLEN + n), PBUF_RAM);
01045   if(!pb) {
01046     LINK_STATS_INC(link.memerr);
01047     LINK_STATS_INC(link.proterr);
01048     snmp_inc_ifoutdiscards(&pc->netif);
01049     return PPPERR_ALLOC;
01050   }
01051 
01052   pbuf_header(pb, -(s16_t)PPPOE_HDRLEN);
01053 
01054   pc->lastXMit = sys_jiffies();
01055 
01056   MEMCPY(pb->payload, s, n);
01057 
01058   if(pppoe_xmit(pc->pppoe_sc, pb) != ERR_OK) {
01059     LINK_STATS_INC(link.err);
01060     snmp_inc_ifoutdiscards(&pc->netif);
01061     return PPPERR_DEVICE;
01062   }
01063 
01064   snmp_add_ifoutoctets(&pc->netif, (u16_t)n);
01065   snmp_inc_ifoutucastpkts(&pc->netif);
01066   LINK_STATS_INC(link.xmit);
01067   return PPPERR_NONE;
01068 }
01069 #endif /* PPPOE_SUPPORT */
01070 
01071 /*
01072  * Write n characters to a ppp link.
01073  *  RETURN: >= 0 Number of characters written
01074  *           -1 Failed to write to device
01075  */
01076 int
01077 pppWrite(int pd, const u_char *s, int n)
01078 {
01079   PPPControl *pc = &pppControl[pd];
01080 #if PPPOS_SUPPORT
01081   u_char c;
01082   u_int fcsOut;
01083   struct pbuf *headMB, *tailMB;
01084 #endif /* PPPOS_SUPPORT */
01085 
01086 #if PPPOE_SUPPORT
01087   if(pc->ethif) {
01088     return pppWriteOverEthernet(pd, s, n);
01089   }
01090 #endif /* PPPOE_SUPPORT */
01091 
01092 #if PPPOS_SUPPORT
01093   headMB = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
01094   if (headMB == NULL) {
01095     LINK_STATS_INC(link.memerr);
01096     LINK_STATS_INC(link.proterr);
01097     snmp_inc_ifoutdiscards(&pc->netif);
01098     return PPPERR_ALLOC;
01099   }
01100 
01101   tailMB = headMB;
01102 
01103   /* If the link has been idle, we'll send a fresh flag character to
01104    * flush any noise. */
01105   if ((sys_jiffies() - pc->lastXMit) >= PPP_MAXIDLEFLAG) {
01106     tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
01107   }
01108   pc->lastXMit = sys_jiffies();
01109 
01110   fcsOut = PPP_INITFCS;
01111   /* Load output buffer. */
01112   while (n-- > 0) {
01113     c = *s++;
01114 
01115     /* Update FCS before checking for special characters. */
01116     fcsOut = PPP_FCS(fcsOut, c);
01117 
01118     /* Copy to output buffer escaping special characters. */
01119     tailMB = pppAppend(c, tailMB, &pc->outACCM);
01120   }
01121     
01122   /* Add FCS and trailing flag. */
01123   c = ~fcsOut & 0xFF;
01124   tailMB = pppAppend(c, tailMB, &pc->outACCM);
01125   c = (~fcsOut >> 8) & 0xFF;
01126   tailMB = pppAppend(c, tailMB, &pc->outACCM);
01127   tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
01128 
01129   /* If we failed to complete the packet, throw it away.
01130    * Otherwise send it. */
01131   if (!tailMB) {
01132     PPPDEBUG(LOG_WARNING,
01133              ("pppWrite[%d]: Alloc err - dropping pbuf len=%d\n", pd, headMB->len));
01134            /*"pppWrite[%d]: Alloc err - dropping %d:%.*H", pd, headMB->len, LWIP_MIN(headMB->len * 2, 40), headMB->payload)); */
01135     pbuf_free(headMB);
01136     LINK_STATS_INC(link.memerr);
01137     LINK_STATS_INC(link.proterr);
01138     snmp_inc_ifoutdiscards(&pc->netif);
01139     return PPPERR_ALLOC;
01140   }
01141 
01142   PPPDEBUG(LOG_INFO, ("pppWrite[%d]: len=%d\n", pd, headMB->len));
01143                    /* "pppWrite[%d]: %d:%.*H", pd, headMB->len, LWIP_MIN(headMB->len * 2, 40), headMB->payload)); */
01144   nPut(pc, headMB);
01145 #endif /* PPPOS_SUPPORT */
01146 
01147   return PPPERR_NONE;
01148 }
01149 
01150 /*
01151  * ppp_send_config - configure the transmit characteristics of
01152  * the ppp interface.
01153  */
01154 void
01155 ppp_send_config( int unit, u16_t mtu, u32_t asyncmap, int pcomp, int accomp)
01156 {
01157   PPPControl *pc = &pppControl[unit];
01158   int i;
01159   
01160   pc->mtu = mtu;
01161   pc->pcomp = pcomp;
01162   pc->accomp = accomp;
01163   
01164   /* Load the ACCM bits for the 32 control codes. */
01165   for (i = 0; i < 32/8; i++) {
01166     pc->outACCM[i] = (u_char)((asyncmap >> (8 * i)) & 0xFF);
01167   }
01168   PPPDEBUG(LOG_INFO, ("ppp_send_config[%d]: outACCM=%X %X %X %X\n",
01169             unit,
01170             pc->outACCM[0], pc->outACCM[1], pc->outACCM[2], pc->outACCM[3]));
01171 }
01172 
01173 
01174 /*
01175  * ppp_set_xaccm - set the extended transmit ACCM for the interface.
01176  */
01177 void
01178 ppp_set_xaccm(int unit, ext_accm *accm)
01179 {
01180   SMEMCPY(pppControl[unit].outACCM, accm, sizeof(ext_accm));
01181   PPPDEBUG(LOG_INFO, ("ppp_set_xaccm[%d]: outACCM=%X %X %X %X\n",
01182             unit,
01183             pppControl[unit].outACCM[0],
01184             pppControl[unit].outACCM[1],
01185             pppControl[unit].outACCM[2],
01186             pppControl[unit].outACCM[3]));
01187 }
01188 
01189 
01190 /*
01191  * ppp_recv_config - configure the receive-side characteristics of
01192  * the ppp interface.
01193  */
01194 void
01195 ppp_recv_config( int unit, int mru, u32_t asyncmap, int pcomp, int accomp)
01196 {
01197   PPPControl *pc = &pppControl[unit];
01198   int i;
01199   SYS_ARCH_DECL_PROTECT(lev);
01200 
01201   LWIP_UNUSED_ARG(accomp);
01202   LWIP_UNUSED_ARG(pcomp);
01203   LWIP_UNUSED_ARG(mru);
01204 
01205   /* Load the ACCM bits for the 32 control codes. */
01206   SYS_ARCH_PROTECT(lev);
01207   for (i = 0; i < 32 / 8; i++) {
01208     /* @todo: does this work? ext_accm has been modified from pppd! */
01209     pc->rx.inACCM[i] = (u_char)(asyncmap >> (i * 8));
01210   }
01211   SYS_ARCH_UNPROTECT(lev);
01212   PPPDEBUG(LOG_INFO, ("ppp_recv_config[%d]: inACCM=%X %X %X %X\n",
01213             unit,
01214             pc->rx.inACCM[0], pc->rx.inACCM[1], pc->rx.inACCM[2], pc->rx.inACCM[3]));
01215 }
01216 
01217 #if 0
01218 /*
01219  * ccp_test - ask kernel whether a given compression method
01220  * is acceptable for use.  Returns 1 if the method and parameters
01221  * are OK, 0 if the method is known but the parameters are not OK
01222  * (e.g. code size should be reduced), or -1 if the method is unknown.
01223  */
01224 int
01225 ccp_test( int unit, int opt_len,  int for_transmit, u_char *opt_ptr)
01226 {
01227   return 0; /* XXX Currently no compression. */
01228 }
01229 
01230 /*
01231  * ccp_flags_set - inform kernel about the current state of CCP.
01232  */
01233 void
01234 ccp_flags_set(int unit, int isopen, int isup)
01235 {
01236   /* XXX */
01237 }
01238 
01239 /*
01240  * ccp_fatal_error - returns 1 if decompression was disabled as a
01241  * result of an error detected after decompression of a packet,
01242  * 0 otherwise.  This is necessary because of patent nonsense.
01243  */
01244 int
01245 ccp_fatal_error(int unit)
01246 {
01247   /* XXX */
01248   return 0;
01249 }
01250 #endif
01251 
01252 /*
01253  * get_idle_time - return how long the link has been idle.
01254  */
01255 int
01256 get_idle_time(int u, struct ppp_idle *ip)
01257 {
01258   /* XXX */
01259   LWIP_UNUSED_ARG(u);
01260   LWIP_UNUSED_ARG(ip);
01261 
01262   return 0;
01263 }
01264 
01265 
01266 /*
01267  * Return user specified netmask, modified by any mask we might determine
01268  * for address `addr' (in network byte order).
01269  * Here we scan through the system's list of interfaces, looking for
01270  * any non-point-to-point interfaces which might appear to be on the same
01271  * network as `addr'.  If we find any, we OR in their netmask to the
01272  * user-specified netmask.
01273  */
01274 u32_t
01275 GetMask(u32_t addr)
01276 {
01277   u32_t mask, nmask;
01278 
01279   htonl(addr);
01280   if (IP_CLASSA(addr)) { /* determine network mask for address class */
01281     nmask = IP_CLASSA_NET;
01282   } else if (IP_CLASSB(addr)) {
01283     nmask = IP_CLASSB_NET;
01284   } else { 
01285     nmask = IP_CLASSC_NET;
01286   }
01287 
01288   /* class D nets are disallowed by bad_ip_adrs */
01289   mask = subnetMask | htonl(nmask);
01290   
01291   /* XXX
01292    * Scan through the system's network interfaces.
01293    * Get each netmask and OR them into our mask.
01294    */
01295 
01296   return mask;
01297 }
01298 
01299 /*
01300  * sifvjcomp - config tcp header compression
01301  */
01302 int
01303 sifvjcomp(int pd, int vjcomp, u8_t cidcomp, u8_t maxcid)
01304 {
01305 #if PPPOS_SUPPORT && VJ_SUPPORT
01306   PPPControl *pc = &pppControl[pd];
01307   
01308   pc->vjEnabled = vjcomp;
01309   pc->vjComp.compressSlot = cidcomp;
01310   pc->vjComp.maxSlotIndex = maxcid;
01311   PPPDEBUG(LOG_INFO, ("sifvjcomp: VJ compress enable=%d slot=%d max slot=%d\n",
01312             vjcomp, cidcomp, maxcid));
01313 #else /* PPPOS_SUPPORT && VJ_SUPPORT */
01314   LWIP_UNUSED_ARG(pd);
01315   LWIP_UNUSED_ARG(vjcomp);
01316   LWIP_UNUSED_ARG(cidcomp);
01317   LWIP_UNUSED_ARG(maxcid);
01318 #endif /* PPPOS_SUPPORT && VJ_SUPPORT */
01319 
01320   return 0;
01321 }
01322 
01323 /*
01324  * pppifNetifInit - netif init callback
01325  */
01326 static err_t
01327 pppifNetifInit(struct netif *netif)
01328 {
01329   netif->name[0] = 'p';
01330   netif->name[1] = 'p';
01331   netif->output = pppifOutput;
01332   netif->mtu = pppMTU((int)(size_t)netif->state);
01333   netif->flags = NETIF_FLAG_POINTTOPOINT | NETIF_FLAG_LINK_UP;
01334 #if LWIP_NETIF_HOSTNAME
01335   /* @todo: Initialize interface hostname */
01336   /* netif_set_hostname(netif, "lwip"); */
01337 #endif /* LWIP_NETIF_HOSTNAME */
01338   return ERR_OK;
01339 }
01340 
01341 
01342 /*
01343  * sifup - Config the interface up and enable IP packets to pass.
01344  */
01345 int
01346 sifup(int pd)
01347 {
01348   PPPControl *pc = &pppControl[pd];
01349   int st = 1;
01350   
01351   if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
01352     st = 0;
01353     PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd));
01354   } else {
01355     netif_remove(&pc->netif);
01356     if (netif_add(&pc->netif, &pc->addrs.our_ipaddr, &pc->addrs.netmask,
01357                   &pc->addrs.his_ipaddr, (void *)(size_t)pd, pppifNetifInit, ip_input)) {
01358       netif_set_up(&pc->netif);
01359       pc->if_up = 1;
01360       pc->errCode = PPPERR_NONE;
01361 
01362       PPPDEBUG(LOG_DEBUG, ("sifup: unit %d: linkStatusCB=%p errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));
01363       if (pc->linkStatusCB) {
01364         pc->linkStatusCB(pc->linkStatusCtx, pc->errCode, &pc->addrs);
01365       }
01366     } else {
01367       st = 0;
01368       PPPDEBUG(LOG_ERR, ("sifup[%d]: netif_add failed\n", pd));
01369     }
01370   }
01371 
01372   return st;
01373 }
01374 
01375 /*
01376  * sifnpmode - Set the mode for handling packets for a given NP.
01377  */
01378 int
01379 sifnpmode(int u, int proto, enum NPmode mode)
01380 {
01381   LWIP_UNUSED_ARG(u);
01382   LWIP_UNUSED_ARG(proto);
01383   LWIP_UNUSED_ARG(mode);
01384   return 0;
01385 }
01386 
01387 /*
01388  * sifdown - Config the interface down and disable IP.
01389  */
01390 int
01391 sifdown(int pd)
01392 {
01393   PPPControl *pc = &pppControl[pd];
01394   int st = 1;
01395   
01396   if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
01397     st = 0;
01398     PPPDEBUG(LOG_WARNING, ("sifdown[%d]: bad parms\n", pd));
01399   } else {
01400     pc->if_up = 0;
01401     /* make sure the netif status callback is called */
01402     netif_set_down(&pc->netif);
01403     netif_remove(&pc->netif);
01404     PPPDEBUG(LOG_DEBUG, ("sifdown: unit %d: linkStatusCB=%p errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));
01405     if (pc->linkStatusCB) {
01406       pc->linkStatusCB(pc->linkStatusCtx, PPPERR_CONNECT, NULL);
01407     }
01408   }
01409   return st;
01410 }
01411 
01412 /**
01413  * sifaddr - Config the interface IP addresses and netmask.
01414  * @param pd Interface unit ???
01415  * @param o Our IP address ???
01416  * @param h His IP address ???
01417  * @param m IP subnet mask ???
01418  * @param ns1 Primary DNS
01419  * @param ns2 Secondary DNS
01420  */
01421 int
01422 sifaddr( int pd, u32_t o, u32_t h, u32_t m, u32_t ns1, u32_t ns2)
01423 {
01424   PPPControl *pc = &pppControl[pd];
01425   int st = 1;
01426   
01427   if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
01428     st = 0;
01429     PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd));
01430   } else {
01431     SMEMCPY(&pc->addrs.our_ipaddr, &o, sizeof(o));
01432     SMEMCPY(&pc->addrs.his_ipaddr, &h, sizeof(h));
01433     SMEMCPY(&pc->addrs.netmask, &m, sizeof(m));
01434     SMEMCPY(&pc->addrs.dns1, &ns1, sizeof(ns1));
01435     SMEMCPY(&pc->addrs.dns2, &ns2, sizeof(ns2));
01436   }
01437   return st;
01438 }
01439 
01440 /**
01441  * cifaddr - Clear the interface IP addresses, and delete routes
01442  * through the interface if possible.
01443  * @param pd Interface unit ???
01444  * @param o Our IP address ???
01445  * @param h IP broadcast address ???
01446  */
01447 int
01448 cifaddr( int pd, u32_t o, u32_t h)
01449 {
01450   PPPControl *pc = &pppControl[pd];
01451   int st = 1;
01452   
01453   LWIP_UNUSED_ARG(o);
01454   LWIP_UNUSED_ARG(h);
01455   if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
01456     st = 0;
01457     PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd));
01458   } else {
01459     IP4_ADDR(&pc->addrs.our_ipaddr, 0,0,0,0);
01460     IP4_ADDR(&pc->addrs.his_ipaddr, 0,0,0,0);
01461     IP4_ADDR(&pc->addrs.netmask, 255,255,255,0);
01462     IP4_ADDR(&pc->addrs.dns1, 0,0,0,0);
01463     IP4_ADDR(&pc->addrs.dns2, 0,0,0,0);
01464   }
01465   return st;
01466 }
01467 
01468 /*
01469  * sifdefaultroute - assign a default route through the address given.
01470  */
01471 int
01472 sifdefaultroute(int pd, u32_t l, u32_t g)
01473 {
01474   PPPControl *pc = &pppControl[pd];
01475   int st = 1;
01476 
01477   LWIP_UNUSED_ARG(l);
01478   LWIP_UNUSED_ARG(g);
01479 
01480   if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
01481     st = 0;
01482     PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd));
01483   } else {
01484     netif_set_default(&pc->netif);
01485   }
01486 
01487   /* TODO: check how PPP handled the netMask, previously not set by ipSetDefault */
01488 
01489   return st;
01490 }
01491 
01492 /*
01493  * cifdefaultroute - delete a default route through the address given.
01494  */
01495 int
01496 cifdefaultroute(int pd, u32_t l, u32_t g)
01497 {
01498   PPPControl *pc = &pppControl[pd];
01499   int st = 1;
01500 
01501   LWIP_UNUSED_ARG(l);
01502   LWIP_UNUSED_ARG(g);
01503 
01504   if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
01505     st = 0;
01506     PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd));
01507   } else {
01508     netif_set_default(NULL);
01509   }
01510 
01511   return st;
01512 }
01513 
01514 /**********************************/
01515 /*** LOCAL FUNCTION DEFINITIONS ***/
01516 /**********************************/
01517 
01518 #if PPPOS_SUPPORT && PPP_INPROC_OWNTHREAD
01519 /* The main PPP process function.  This implements the state machine according
01520  * to section 4 of RFC 1661: The Point-To-Point Protocol. */
01521 static void
01522 pppInputThread(void *arg)
01523 {
01524   int count;
01525   PPPControlRx *pcrx = arg;
01526 
01527   do
01528   {
01529     sys_arch_mbox_fetch(&pppMboxStart, (void**)&pcrx, 0); //Wait indefinitely
01530     PPPDEBUG(LOG_INFO, ("pppInputThread: unit %d: Woken up\n", pcrx->pd));
01531     while (lcp_phase[pcrx->pd] != PHASE_DEAD) {
01532       count = sio_read(pcrx->fd, pcrx->rxbuf, PPPOS_RX_BUFSIZE);
01533       if(count > 0) {
01534         sys_mutex_lock(&pppMtx);
01535         pppInProc(pcrx, pcrx->rxbuf, count);
01536         sys_mutex_unlock(&pppMtx);
01537       } else {
01538         /* nothing received, give other tasks a chance to run */
01539         sys_msleep(1);
01540       }
01541      
01542     }
01543     PPPDEBUG(LOG_INFO, ("pppInputThread: unit %d: Released\n", pcrx->pd));
01544     sys_mbox_post(&pppMboxStopped, (void*)pcrx);
01545   } while(1); //Never terminates
01546 }
01547 #endif /* PPPOS_SUPPORT && PPP_INPROC_OWNTHREAD */
01548 
01549 #if PPPOE_SUPPORT
01550 
01551 void
01552 pppOverEthernetInitFailed(int pd)
01553 {
01554   PPPControl* pc;
01555 
01556   pppHup(pd);
01557   pppStop(pd);
01558 
01559   pc = &pppControl[pd];
01560   pppoe_destroy(&pc->netif);
01561   pc->openFlag = 0;
01562 
01563   if(pc->linkStatusCB) {
01564     pc->linkStatusCB(pc->linkStatusCtx, pc->errCode ? pc->errCode : PPPERR_PROTOCOL, NULL);
01565   }
01566 }
01567 
01568 static void
01569 pppOverEthernetLinkStatusCB(int pd, int up)
01570 {
01571   if(up) {
01572     PPPDEBUG(LOG_INFO, ("pppOverEthernetLinkStatusCB: unit %d: Connecting\n", pd));
01573     pppStart(pd);
01574   } else {
01575     pppOverEthernetInitFailed(pd);
01576   }
01577 }
01578 #endif /* PPPOE_SUPPORT */
01579 
01580 struct pbuf *
01581 pppSingleBuf(struct pbuf *p)
01582 {
01583   struct pbuf *q, *b;
01584   u_char *pl;
01585 
01586   if(p->tot_len == p->len) {
01587     return p;
01588   }
01589 
01590   q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
01591   if(!q) {
01592     PPPDEBUG(LOG_ERR,
01593              ("pppSingleBuf: unable to alloc new buf (%d)\n", p->tot_len));
01594     return p; /* live dangerously */
01595   }
01596 
01597   for(b = p, pl = q->payload; b != NULL; b = b->next) {
01598     MEMCPY(pl, b->payload, b->len);
01599     pl += b->len;
01600   }
01601 
01602   pbuf_free(p);
01603 
01604   return q;
01605 }
01606 
01607 struct pppInputHeader {
01608   int unit;
01609   u16_t proto;
01610 };
01611 
01612 /*
01613  * Pass the processed input packet to the appropriate handler.
01614  * This function and all handlers run in the context of the tcpip_thread
01615  */
01616 static void
01617 pppInput(void *arg)
01618 {
01619   struct pbuf *nb = (struct pbuf *)arg;
01620   u16_t protocol;
01621   int pd;
01622 
01623   pd = ((struct pppInputHeader *)nb->payload)->unit;
01624   protocol = ((struct pppInputHeader *)nb->payload)->proto;
01625     
01626   if(pbuf_header(nb, -(int)sizeof(struct pppInputHeader))) {
01627     LWIP_ASSERT("pbuf_header failed\n", 0);
01628     goto drop;
01629   }
01630 
01631   LINK_STATS_INC(link.recv);
01632   snmp_inc_ifinucastpkts(&pppControl[pd].netif);
01633   snmp_add_ifinoctets(&pppControl[pd].netif, nb->tot_len);
01634 
01635   /*
01636    * Toss all non-LCP packets unless LCP is OPEN.
01637    * Until we get past the authentication phase, toss all packets
01638    * except LCP, LQR and authentication packets.
01639    */
01640   if((lcp_phase[pd] <= PHASE_AUTHENTICATE) && (protocol != PPP_LCP)) {
01641     if(!((protocol == PPP_LQR) || (protocol == PPP_PAP) || (protocol == PPP_CHAP)) ||
01642         (lcp_phase[pd] != PHASE_AUTHENTICATE)) {
01643       PPPDEBUG(LOG_INFO, ("pppInput: discarding proto 0x%"X16_F" in phase %d\n", protocol, lcp_phase[pd]));
01644       goto drop;
01645     }
01646   }
01647 
01648   switch(protocol) {
01649     case PPP_VJC_COMP:      /* VJ compressed TCP */
01650 #if PPPOS_SUPPORT && VJ_SUPPORT
01651       PPPDEBUG(LOG_INFO, ("pppInput[%d]: vj_comp in pbuf len=%d\n", pd, nb->len));
01652       /*
01653        * Clip off the VJ header and prepend the rebuilt TCP/IP header and
01654        * pass the result to IP.
01655        */
01656       if ((vj_uncompress_tcp(&nb, &pppControl[pd].vjComp) >= 0) && (pppControl[pd].netif.input)) {
01657         pppControl[pd].netif.input(nb, &pppControl[pd].netif);
01658         return;
01659       }
01660       /* Something's wrong so drop it. */
01661       PPPDEBUG(LOG_WARNING, ("pppInput[%d]: Dropping VJ compressed\n", pd));
01662 #else  /* PPPOS_SUPPORT && VJ_SUPPORT */
01663       /* No handler for this protocol so drop the packet. */
01664       PPPDEBUG(LOG_INFO, ("pppInput[%d]: drop VJ Comp in %d:%s\n", pd, nb->len, nb->payload));
01665 #endif /* PPPOS_SUPPORT && VJ_SUPPORT */
01666       break;
01667 
01668     case PPP_VJC_UNCOMP:    /* VJ uncompressed TCP */
01669 #if PPPOS_SUPPORT && VJ_SUPPORT
01670       PPPDEBUG(LOG_INFO, ("pppInput[%d]: vj_un in pbuf len=%d\n", pd, nb->len));
01671       /*
01672        * Process the TCP/IP header for VJ header compression and then pass
01673        * the packet to IP.
01674        */
01675       if ((vj_uncompress_uncomp(nb, &pppControl[pd].vjComp) >= 0) && pppControl[pd].netif.input) {
01676         pppControl[pd].netif.input(nb, &pppControl[pd].netif);
01677         return;
01678       }
01679       /* Something's wrong so drop it. */
01680       PPPDEBUG(LOG_WARNING, ("pppInput[%d]: Dropping VJ uncompressed\n", pd));
01681 #else  /* PPPOS_SUPPORT && VJ_SUPPORT */
01682       /* No handler for this protocol so drop the packet. */
01683       PPPDEBUG(LOG_INFO,
01684                ("pppInput[%d]: drop VJ UnComp in %d:.*H\n", 
01685                 pd, nb->len, LWIP_MIN(nb->len * 2, 40), nb->payload));
01686 #endif /* PPPOS_SUPPORT && VJ_SUPPORT */
01687       break;
01688 
01689     case PPP_IP:            /* Internet Protocol */
01690       PPPDEBUG(LOG_INFO, ("pppInput[%d]: ip in pbuf len=%d\n", pd, nb->len));
01691       if (pppControl[pd].netif.input) {
01692         pppControl[pd].netif.input(nb, &pppControl[pd].netif);
01693         return;
01694       }
01695       break;
01696 
01697     default: {
01698       struct protent *protp;
01699       int i;
01700 
01701       /*
01702        * Upcall the proper protocol input routine.
01703        */
01704       for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) {
01705         if (protp->protocol == protocol && protp->enabled_flag) {
01706           PPPDEBUG(LOG_INFO, ("pppInput[%d]: %s len=%d\n", pd, protp->name, nb->len));
01707           nb = pppSingleBuf(nb);
01708           (*protp->input)(pd, nb->payload, nb->len);
01709           PPPDEBUG(LOG_DETAIL, ("pppInput[%d]: packet processed\n", pd));
01710           goto out;
01711         }
01712       }
01713 
01714       /* No handler for this protocol so reject the packet. */
01715       PPPDEBUG(LOG_INFO, ("pppInput[%d]: rejecting unsupported proto 0x%"X16_F" len=%d\n", pd, protocol, nb->len));
01716       if (pbuf_header(nb, sizeof(protocol))) {
01717         LWIP_ASSERT("pbuf_header failed\n", 0);
01718         goto drop;
01719       }
01720 #if BYTE_ORDER == LITTLE_ENDIAN
01721       protocol = htons(protocol);
01722 #endif /* BYTE_ORDER == LITTLE_ENDIAN */
01723       SMEMCPY(nb->payload, &protocol, sizeof(protocol));
01724       lcp_sprotrej(pd, nb->payload, nb->len);
01725     }
01726     break;
01727   }
01728 
01729 drop:
01730   LINK_STATS_INC(link.drop);
01731   snmp_inc_ifindiscards(&pppControl[pd].netif);
01732 
01733 out:
01734   pbuf_free(nb);
01735   return;
01736 }
01737 
01738 #if PPPOS_SUPPORT
01739 /*
01740  * Drop the input packet.
01741  */
01742 static void
01743 pppFreeCurrentInputPacket(PPPControlRx *pcrx)
01744 {
01745   if (pcrx->inHead != NULL) {
01746     if (pcrx->inTail && (pcrx->inTail != pcrx->inHead)) {
01747       pbuf_free(pcrx->inTail);
01748     }
01749     pbuf_free(pcrx->inHead);
01750     pcrx->inHead = NULL;
01751   }
01752   pcrx->inTail = NULL;
01753 }
01754 
01755 /*
01756  * Drop the input packet and increase error counters.
01757  */
01758 static void
01759 pppDrop(PPPControlRx *pcrx)
01760 {
01761   if (pcrx->inHead != NULL) {
01762 #if 0
01763     PPPDEBUG(LOG_INFO, ("pppDrop: %d:%.*H\n", pcrx->inHead->len, min(60, pcrx->inHead->len * 2), pcrx->inHead->payload));
01764 #endif
01765     PPPDEBUG(LOG_INFO, ("pppDrop: pbuf len=%d, addr %p\n", pcrx->inHead->len, (void*)pcrx->inHead));
01766   }
01767   pppFreeCurrentInputPacket(pcrx); //backport from lwip 1.4.1
01768 #if VJ_SUPPORT
01769   vj_uncompress_err(&pppControl[pcrx->pd].vjComp);
01770 #endif /* VJ_SUPPORT */
01771 
01772   LINK_STATS_INC(link.drop);
01773   snmp_inc_ifindiscards(&pppControl[pcrx->pd].netif);
01774 }
01775 
01776 /** Pass received raw characters to PPPoS to be decoded. This function is
01777  * thread-safe and can be called from a dedicated RX-thread or from a main-loop.
01778  *
01779  * @param pd PPP descriptor index, returned by pppOpen()
01780  * @param data received data
01781  * @param len length of received data
01782  */
01783 void
01784 pppos_input(int pd, u_char* data, int len)
01785 {
01786   pppInProc(&pppControl[pd].rx, data, len);
01787 }
01788 
01789 /**
01790  * Process a received octet string.
01791  */
01792 static void
01793 pppInProc(PPPControlRx *pcrx, u_char *s, int l)
01794 {
01795   struct pbuf *nextNBuf;
01796   u_char curChar;
01797   u_char escaped;
01798   SYS_ARCH_DECL_PROTECT(lev);
01799 
01800   PPPDEBUG(LOG_DEBUG, ("pppInProc[%d]: got %d bytes\n", pcrx->pd, l));
01801   while (l-- > 0) {
01802     curChar = *s++;
01803 
01804     SYS_ARCH_PROTECT(lev);
01805     escaped = ESCAPE_P(pcrx->inACCM, curChar);
01806     SYS_ARCH_UNPROTECT(lev);
01807     /* Handle special characters. */
01808     if (escaped) {
01809       /* Check for escape sequences. */
01810       /* XXX Note that this does not handle an escaped 0x5d character which
01811        * would appear as an escape character.  Since this is an ASCII ']'
01812        * and there is no reason that I know of to escape it, I won't complicate
01813        * the code to handle this case. GLL */
01814       if (curChar == PPP_ESCAPE) {
01815         pcrx->inEscaped = 1;
01816       /* Check for the flag character. */
01817       } else if (curChar == PPP_FLAG) {
01818         /* If this is just an extra flag character, ignore it. */
01819         if (pcrx->inState <= PDADDRESS) {
01820           /* ignore it */;
01821         /* If we haven't received the packet header, drop what has come in. */
01822         } else if (pcrx->inState < PDDATA) {
01823           PPPDEBUG(LOG_WARNING,
01824                    ("pppInProc[%d]: Dropping incomplete packet %d\n", 
01825                     pcrx->pd, pcrx->inState));
01826           LINK_STATS_INC(link.lenerr);
01827           pppDrop(pcrx);
01828         /* If the fcs is invalid, drop the packet. */
01829         } else if (pcrx->inFCS != PPP_GOODFCS) {
01830           PPPDEBUG(LOG_INFO,
01831                    ("pppInProc[%d]: Dropping bad fcs 0x%"X16_F" proto=0x%"X16_F"\n", 
01832                     pcrx->pd, pcrx->inFCS, pcrx->inProtocol));
01833           /* Note: If you get lots of these, check for UART frame errors or try different baud rate */
01834           LINK_STATS_INC(link.chkerr);
01835           pppDrop(pcrx);
01836         /* Otherwise it's a good packet so pass it on. */
01837         } else {
01838           struct pbuf *inp;
01839           /* Trim off the checksum. */
01840           if(pcrx->inTail->len >= 2) {
01841             pcrx->inTail->len -= 2;
01842 
01843             pcrx->inTail->tot_len = pcrx->inTail->len;
01844             if (pcrx->inTail != pcrx->inHead) {
01845               pbuf_cat(pcrx->inHead, pcrx->inTail);
01846             }
01847           } else {
01848             pcrx->inTail->tot_len = pcrx->inTail->len;
01849             if (pcrx->inTail != pcrx->inHead) {
01850               pbuf_cat(pcrx->inHead, pcrx->inTail);
01851             }
01852 
01853             pbuf_realloc(pcrx->inHead, pcrx->inHead->tot_len - 2);
01854           }
01855 
01856           /* Dispatch the packet thereby consuming it. */
01857           inp = pcrx->inHead;
01858           /* Packet consumed, release our references. */
01859           pcrx->inHead = NULL;
01860           pcrx->inTail = NULL;
01861 #if PPP_INPROC_MULTITHREADED
01862           if(tcpip_callback_with_block(pppInput, inp, 0) != ERR_OK) {
01863             PPPDEBUG(LOG_ERR, ("pppInProc[%d]: tcpip_callback() failed, dropping packet\n", pcrx->pd));
01864             pbuf_free(inp);
01865             LINK_STATS_INC(link.drop);
01866             snmp_inc_ifindiscards(&pppControl[pcrx->pd].netif);
01867           }
01868 #else /* PPP_INPROC_MULTITHREADED */
01869           pppInput(inp);
01870 #endif /* PPP_INPROC_MULTITHREADED */
01871         }
01872 
01873         /* Prepare for a new packet. */
01874         pcrx->inFCS = PPP_INITFCS;
01875         pcrx->inState = PDADDRESS;
01876         pcrx->inEscaped = 0;
01877       /* Other characters are usually control characters that may have
01878        * been inserted by the physical layer so here we just drop them. */
01879       } else {
01880         PPPDEBUG(LOG_WARNING,
01881                  ("pppInProc[%d]: Dropping ACCM char <%d>\n", pcrx->pd, curChar));
01882       }
01883     /* Process other characters. */
01884     } else {
01885       /* Unencode escaped characters. */
01886       if (pcrx->inEscaped) {
01887         pcrx->inEscaped = 0;
01888         curChar ^= PPP_TRANS;
01889       }
01890 
01891       /* Process character relative to current state. */
01892       switch(pcrx->inState) {
01893         case PDIDLE:                    /* Idle state - waiting. */
01894           /* Drop the character if it's not 0xff
01895            * we would have processed a flag character above. */
01896           if (curChar != PPP_ALLSTATIONS) {
01897             break;
01898           }
01899 
01900         /* Fall through */
01901         case PDSTART:                   /* Process start flag. */
01902           /* Prepare for a new packet. */
01903           pcrx->inFCS = PPP_INITFCS;
01904 
01905         /* Fall through */
01906         case PDADDRESS:                 /* Process address field. */
01907           if (curChar == PPP_ALLSTATIONS) {
01908             pcrx->inState = PDCONTROL;
01909             break;
01910           }
01911           /* Else assume compressed address and control fields so
01912            * fall through to get the protocol... */
01913         case PDCONTROL:                 /* Process control field. */
01914           /* If we don't get a valid control code, restart. */
01915           if (curChar == PPP_UI) {
01916             pcrx->inState = PDPROTOCOL1;
01917             break;
01918           }
01919 #if 0
01920           else {
01921             PPPDEBUG(LOG_WARNING,
01922                      ("pppInProc[%d]: Invalid control <%d>\n", pcrx->pd, curChar));
01923             pcrx->inState = PDSTART;
01924           }
01925 #endif
01926         case PDPROTOCOL1:               /* Process protocol field 1. */
01927           /* If the lower bit is set, this is the end of the protocol
01928            * field. */
01929           if (curChar & 1) {
01930             pcrx->inProtocol = curChar;
01931             pcrx->inState = PDDATA;
01932           } else {
01933             pcrx->inProtocol = (u_int)curChar << 8;
01934             pcrx->inState = PDPROTOCOL2;
01935           }
01936           break;
01937         case PDPROTOCOL2:               /* Process protocol field 2. */
01938           pcrx->inProtocol |= curChar;
01939           pcrx->inState = PDDATA;
01940           break;
01941         case PDDATA:                    /* Process data byte. */
01942           /* Make space to receive processed data. */
01943           if (pcrx->inTail == NULL || pcrx->inTail->len == PBUF_POOL_BUFSIZE) {
01944             if (pcrx->inTail != NULL) {
01945               pcrx->inTail->tot_len = pcrx->inTail->len;
01946               if (pcrx->inTail != pcrx->inHead) {
01947                 pbuf_cat(pcrx->inHead, pcrx->inTail);
01948                 /* give up the inTail reference now */
01949                 pcrx->inTail = NULL;
01950               }
01951             }
01952             /* If we haven't started a packet, we need a packet header. */
01953             nextNBuf = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
01954             if (nextNBuf == NULL) {
01955               /* No free buffers.  Drop the input packet and let the
01956                * higher layers deal with it.  Continue processing
01957                * the received pbuf chain in case a new packet starts. */
01958               PPPDEBUG(LOG_ERR, ("pppInProc[%d]: NO FREE MBUFS!\n", pcrx->pd));
01959               LINK_STATS_INC(link.memerr);
01960               pppDrop(pcrx);
01961               pcrx->inState = PDSTART;  /* Wait for flag sequence. */
01962               break;
01963             }
01964             if (pcrx->inHead == NULL) {
01965               struct pppInputHeader *pih = nextNBuf->payload;
01966 
01967               pih->unit = pcrx->pd;
01968               pih->proto = pcrx->inProtocol;
01969 
01970               nextNBuf->len += sizeof(*pih);
01971 
01972               pcrx->inHead = nextNBuf;
01973             }
01974             pcrx->inTail = nextNBuf;
01975           }
01976           /* Load character into buffer. */
01977           ((u_char*)pcrx->inTail->payload)[pcrx->inTail->len++] = curChar;
01978           break;
01979       }
01980 
01981       /* update the frame check sequence number. */
01982       pcrx->inFCS = PPP_FCS(pcrx->inFCS, curChar);
01983     }
01984   } /* while (l-- > 0), all bytes processed */
01985 
01986   avRandomize();
01987 }
01988 #endif /* PPPOS_SUPPORT */
01989 
01990 #if PPPOE_SUPPORT
01991 void
01992 pppInProcOverEthernet(int pd, struct pbuf *pb)
01993 {
01994   struct pppInputHeader *pih;
01995   u16_t inProtocol;
01996 
01997   if(pb->len < sizeof(inProtocol)) {
01998     PPPDEBUG(LOG_ERR, ("pppInProcOverEthernet: too small for protocol field\n"));
01999     goto drop;
02000   }
02001 
02002   inProtocol = (((u8_t *)pb->payload)[0] << 8) | ((u8_t*)pb->payload)[1];
02003 
02004   /* make room for pppInputHeader - should not fail */
02005   if (pbuf_header(pb, sizeof(*pih) - sizeof(inProtocol)) != 0) {
02006     PPPDEBUG(LOG_ERR, ("pppInProcOverEthernet: could not allocate room for header\n"));
02007     goto drop;
02008   }
02009 
02010   pih = pb->payload;
02011 
02012   pih->unit = pd;
02013   pih->proto = inProtocol;
02014 
02015   /* Dispatch the packet thereby consuming it. */
02016   pppInput(pb);
02017   return;
02018 
02019 drop:
02020   LINK_STATS_INC(link.drop);
02021   snmp_inc_ifindiscards(&pppControl[pd].netif);
02022   pbuf_free(pb);
02023   return;
02024 }
02025 #endif /* PPPOE_SUPPORT */
02026 
02027 #if LWIP_NETIF_STATUS_CALLBACK
02028 /** Set the status callback of a PPP's netif
02029  *
02030  * @param pd The PPP descriptor returned by pppOpen()
02031  * @param status_callback pointer to the status callback function
02032  *
02033  * @see netif_set_status_callback
02034  */
02035 void
02036 ppp_set_netif_statuscallback(int pd, netif_status_callback_fn status_callback)
02037 {
02038   netif_set_status_callback(&pppControl[pd].netif, status_callback); 
02039 }
02040 #endif /* LWIP_NETIF_STATUS_CALLBACK */
02041 
02042 #if LWIP_NETIF_LINK_CALLBACK
02043 /** Set the link callback of a PPP's netif
02044  *
02045  * @param pd The PPP descriptor returned by pppOpen()
02046  * @param link_callback pointer to the link callback function
02047  *
02048  * @see netif_set_link_callback
02049  */
02050 void
02051 ppp_set_netif_linkcallback(int pd, netif_status_callback_fn link_callback)
02052 {
02053   netif_set_link_callback(&pppControl[pd].netif, link_callback); 
02054 }
02055 #endif /* LWIP_NETIF_LINK_CALLBACK */
02056 
02057 #endif /* PPP_SUPPORT */