Bonjour/Zerconf library

Dependencies:   mbed

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