Dependents:   TimeZoneDemo EthernetJackTestCode MMEx_Challenge ntp_mem ... more

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