Ethernet for Nucleo and Disco board STM32F746 works with gcc and arm. IAC is untested

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