Adapted to Lora Semtech + Nucleo

Dependencies:   DebugLib

Dependents:   LoRaWAN-lmic-app LoRaWAN-lmic-app LoRaWAN-test-10secs LoRaPersonalizedDeviceForEverynet ... more

Fork of lwip_ppp_ethernet by Donatien Garnier

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 #define __LWIP_ORIG 0
00083 
00084 #include "lwip/opt.h"
00085 
00086 #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
00087 
00088 #include "lwip/ip.h" /* for ip_input() */
00089 
00090 #include "ppp.h"
00091 #include "pppdebug.h"
00092 
00093 #include "randm.h"
00094 #include "fsm.h"
00095 #if PAP_SUPPORT
00096 #include "pap.h"
00097 #endif /* PAP_SUPPORT */
00098 #if CHAP_SUPPORT
00099 #include "chap.h"
00100 #endif /* CHAP_SUPPORT */
00101 #include "ipcp.h"
00102 #include "lcp.h"
00103 #include "magic.h"
00104 #include "auth.h"
00105 #if VJ_SUPPORT
00106 #include "vj.h"
00107 #endif /* VJ_SUPPORT */
00108 #if PPPOE_SUPPORT
00109 #include "netif/ppp_oe.h"
00110 #endif /* PPPOE_SUPPORT */
00111 
00112 #include "lwip/tcpip.h"
00113 #include "lwip/api.h"
00114 #include "lwip/snmp.h"
00115 
00116 #include <string.h>
00117 
00118 /*************************/
00119 /*** LOCAL DEFINITIONS ***/
00120 /*************************/
00121 
00122 /** PPP_INPROC_MULTITHREADED==1 call pppInput using tcpip_callback().
00123  * Set this to 0 if pppInProc is called inside tcpip_thread or with NO_SYS==1.
00124  * Default is 1 for NO_SYS==0 (multithreaded) and 0 for NO_SYS==1 (single-threaded).
00125  */
00126 #ifndef PPP_INPROC_MULTITHREADED
00127 #define PPP_INPROC_MULTITHREADED (NO_SYS==0)
00128 #endif
00129 
00130 /** PPP_INPROC_OWNTHREAD==1: start a dedicated RX thread per PPP session.
00131  * Default is 0: call pppos_input() for received raw characters, charcater
00132  * reception is up to the port */
00133 #ifndef PPP_INPROC_OWNTHREAD
00134 #define PPP_INPROC_OWNTHREAD      PPP_INPROC_MULTITHREADED
00135 #endif
00136 
00137 #if PPP_INPROC_OWNTHREAD && !PPP_INPROC_MULTITHREADED
00138   #error "PPP_INPROC_OWNTHREAD needs PPP_INPROC_MULTITHREADED==1"
00139 #endif
00140 
00141 /*
00142  * The basic PPP frame.
00143  */
00144 #define PPP_ADDRESS(p)  (((u_char *)(p))[0])
00145 #define PPP_CONTROL(p)  (((u_char *)(p))[1])
00146 #define PPP_PROTOCOL(p) ((((u_char *)(p))[2] << 8) + ((u_char *)(p))[3])
00147 
00148 /* PPP packet parser states.  Current state indicates operation yet to be
00149  * completed. */
00150 typedef enum {
00151   PDIDLE = 0,  /* Idle state - waiting. */
00152   PDSTART,     /* Process start flag. */
00153   PDADDRESS,   /* Process address field. */
00154   PDCONTROL,   /* Process control field. */
00155   PDPROTOCOL1, /* Process protocol field 1. */
00156   PDPROTOCOL2, /* Process protocol field 2. */
00157   PDDATA       /* Process data byte. */
00158 } PPPDevStates;
00159 
00160 #define ESCAPE_P(accm, c) ((accm)[(c) >> 3] & pppACCMMask[c & 0x07])
00161 
00162 /************************/
00163 /*** LOCAL DATA TYPES ***/
00164 /************************/
00165 
00166 /** RX buffer size: this may be configured smaller! */
00167 #ifndef PPPOS_RX_BUFSIZE
00168 #define PPPOS_RX_BUFSIZE    (PPP_MRU + PPP_HDRLEN)
00169 #endif
00170 
00171 typedef struct PPPControlRx_s {
00172   /** unit number / ppp descriptor */
00173   int pd;
00174   /** the rx file descriptor */
00175   sio_fd_t fd;
00176   /** receive buffer - encoded data is stored here */
00177   u_char rxbuf[PPPOS_RX_BUFSIZE];
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 #endif /* PPPOS_SUPPORT */
00247 
00248 
00249 /******************************/
00250 /*** PUBLIC DATA STRUCTURES ***/
00251 /******************************/
00252 u_long subnetMask;
00253 
00254 static PPPControl pppControl[NUM_PPP] __attribute((section("AHBSRAM1"))); //Add DG; /* The PPP interface control blocks. */
00255 
00256 #if !__LWIP_ORIG
00257     sys_mbox_t pppMbox; //Used to signal PPP thread that a PPP session begins
00258 #endif
00259 
00260 /*
00261  * PPP Data Link Layer "protocol" table.
00262  * One entry per supported protocol.
00263  * The last entry must be NULL.
00264  */
00265 struct protent *ppp_protocols[] = {
00266   &lcp_protent,
00267 #if PAP_SUPPORT
00268   &pap_protent,
00269 #endif /* PAP_SUPPORT */
00270 #if CHAP_SUPPORT
00271   &chap_protent,
00272 #endif /* CHAP_SUPPORT */
00273 #if CBCP_SUPPORT
00274   &cbcp_protent,
00275 #endif /* CBCP_SUPPORT */
00276   &ipcp_protent,
00277 #if CCP_SUPPORT
00278   &ccp_protent,
00279 #endif /* CCP_SUPPORT */
00280   NULL
00281 };
00282 
00283 
00284 /*
00285  * Buffers for outgoing packets.  This must be accessed only from the appropriate
00286  * PPP task so that it doesn't need to be protected to avoid collisions.
00287  */
00288 u_char outpacket_buf[NUM_PPP][PPP_MRU+PPP_HDRLEN] __attribute((section("AHBSRAM1")));
00289 
00290 
00291 /*****************************/
00292 /*** LOCAL DATA STRUCTURES ***/
00293 /*****************************/
00294 
00295 #if PPPOS_SUPPORT
00296 /*
00297  * FCS lookup table as calculated by genfcstab.
00298  * @todo: smaller, slower implementation for lower memory footprint?
00299  */
00300 static const u_short fcstab[256] = {
00301   0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
00302   0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
00303   0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
00304   0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
00305   0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
00306   0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
00307   0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
00308   0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
00309   0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
00310   0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
00311   0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
00312   0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
00313   0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
00314   0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
00315   0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
00316   0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
00317   0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
00318   0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
00319   0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
00320   0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
00321   0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
00322   0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
00323   0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
00324   0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
00325   0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
00326   0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
00327   0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
00328   0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
00329   0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
00330   0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
00331   0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
00332   0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
00333 };
00334 
00335 /* PPP's Asynchronous-Control-Character-Map.  The mask array is used
00336  * to select the specific bit for a character. */
00337 static u_char pppACCMMask[] = {
00338   0x01,
00339   0x02,
00340   0x04,
00341   0x08,
00342   0x10,
00343   0x20,
00344   0x40,
00345   0x80
00346 };
00347 
00348 /** Wake up the task blocked in reading from serial line (if any) */
00349 static void
00350 pppRecvWakeup(int pd)
00351 {
00352   PPPDEBUG(LOG_DEBUG, ("pppRecvWakeup: unit %d\n", pd));
00353   if (pppControl[pd].openFlag != 0) {
00354     sio_read_abort(pppControl[pd].fd);
00355   }
00356 }
00357 #endif /* PPPOS_SUPPORT */
00358 
00359 void
00360 pppLinkTerminated(int pd)
00361 {
00362   PPPDEBUG(LOG_DEBUG, ("pppLinkTerminated: unit %d\n", pd));
00363 
00364 #if PPPOE_SUPPORT
00365   if (pppControl[pd].ethif) {
00366     pppoe_disconnect(pppControl[pd].pppoe_sc);
00367   } else
00368 #endif /* PPPOE_SUPPORT */
00369   {
00370 #if PPPOS_SUPPORT
00371     PPPControl* pc;
00372     pppRecvWakeup(pd);
00373     pc = &pppControl[pd];
00374 
00375     PPPDEBUG(LOG_DEBUG, ("pppLinkTerminated: unit %d: linkStatusCB=%p errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));
00376     if (pc->linkStatusCB) {
00377       pc->linkStatusCB(pc->linkStatusCtx, pc->errCode ? pc->errCode : PPPERR_PROTOCOL, NULL);
00378     }
00379 
00380     pc->openFlag = 0;/**/
00381 #endif /* PPPOS_SUPPORT */
00382   }
00383   PPPDEBUG(LOG_DEBUG, ("pppLinkTerminated: finished.\n"));
00384 }
00385 
00386 void
00387 pppLinkDown(int pd)
00388 {
00389   PPPDEBUG(LOG_DEBUG, ("pppLinkDown: unit %d\n", pd));
00390 
00391 #if PPPOE_SUPPORT
00392   if (pppControl[pd].ethif) {
00393     pppoe_disconnect(pppControl[pd].pppoe_sc);
00394   } else
00395 #endif /* PPPOE_SUPPORT */
00396   {
00397 #if PPPOS_SUPPORT
00398     pppRecvWakeup(pd);
00399 #endif /* PPPOS_SUPPORT */
00400   }
00401 }
00402 
00403 /** Initiate LCP open request */
00404 static void
00405 pppStart(int pd)
00406 {
00407   PPPDEBUG(LOG_DEBUG, ("pppStart: unit %d\n", pd));
00408   lcp_lowerup(pd);
00409   lcp_open(pd); /* Start protocol */
00410   PPPDEBUG(LOG_DEBUG, ("pppStart: finished\n"));
00411 }
00412 
00413 /** LCP close request */
00414 static void
00415 pppStop(int pd)
00416 {
00417   PPPDEBUG(LOG_DEBUG, ("pppStop: unit %d\n", pd));
00418   lcp_close(pd, "User request");
00419 }
00420 
00421 /** Called when carrier/link is lost */
00422 static void
00423 pppHup(int pd)
00424 {
00425   PPPDEBUG(LOG_DEBUG, ("pppHupCB: unit %d\n", pd));
00426   lcp_lowerdown(pd);
00427   link_terminated(pd);
00428 }
00429 
00430 /***********************************/
00431 /*** PUBLIC FUNCTION DEFINITIONS ***/
00432 /***********************************/
00433 /* Initialize the PPP subsystem. */
00434 
00435 struct ppp_settings ppp_settings;
00436 
00437 void
00438 pppInit(void)
00439 {
00440   struct protent *protp;
00441   int i, j;
00442 
00443   memset(&ppp_settings, 0, sizeof(ppp_settings));
00444   ppp_settings.usepeerdns = 1;
00445   pppSetAuth(PPPAUTHTYPE_NONE, NULL, NULL);
00446 
00447   magicInit();
00448 
00449   subnetMask = PP_HTONL(0xffffff00UL);
00450 
00451   for (i = 0; i < NUM_PPP; i++) {
00452     /* Initialize each protocol to the standard option set. */
00453     for (j = 0; (protp = ppp_protocols[j]) != NULL; ++j) {
00454       (*protp->init)(i);
00455     }
00456   }
00457 
00458   #if !__LWIP_ORIG
00459   sys_mbox_new(&pppMbox, 1);
00460   sys_thread_new(PPP_THREAD_NAME, pppInputThread, (void*)NULL, PPP_THREAD_STACKSIZE, PPP_THREAD_PRIO); //Create PPP thread here
00461   #endif
00462 }
00463 
00464 void
00465 pppSetAuth(enum pppAuthType authType, const char *user, const char *passwd)
00466 {
00467   switch(authType) {
00468     case PPPAUTHTYPE_NONE:
00469     default:
00470 #ifdef LWIP_PPP_STRICT_PAP_REJECT
00471       ppp_settings.refuse_pap = 1;
00472 #else  /* LWIP_PPP_STRICT_PAP_REJECT */
00473       /* some providers request pap and accept an empty login/pw */
00474       ppp_settings.refuse_pap = 0;
00475 #endif /* LWIP_PPP_STRICT_PAP_REJECT */
00476       ppp_settings.refuse_chap = 1;
00477       break;
00478 
00479     case PPPAUTHTYPE_ANY:
00480       /* Warning: Using PPPAUTHTYPE_ANY might have security consequences.
00481        * RFC 1994 says:
00482        *
00483        * In practice, within or associated with each PPP server, there is a
00484        * database which associates "user" names with authentication
00485        * information ("secrets").  It is not anticipated that a particular
00486        * named user would be authenticated by multiple methods.  This would
00487        * make the user vulnerable to attacks which negotiate the least secure
00488        * method from among a set (such as PAP rather than CHAP).  If the same
00489        * secret was used, PAP would reveal the secret to be used later with
00490        * CHAP.
00491        *
00492        * Instead, for each user name there should be an indication of exactly
00493        * one method used to authenticate that user name.  If a user needs to
00494        * make use of different authentication methods under different
00495        * circumstances, then distinct user names SHOULD be employed, each of
00496        * which identifies exactly one authentication method.
00497        *
00498        */
00499       ppp_settings.refuse_pap = 0;
00500       ppp_settings.refuse_chap = 0;
00501       break;
00502 
00503     case PPPAUTHTYPE_PAP:
00504       ppp_settings.refuse_pap = 0;
00505       ppp_settings.refuse_chap = 1;
00506       break;
00507 
00508     case PPPAUTHTYPE_CHAP:
00509       ppp_settings.refuse_pap = 1;
00510       ppp_settings.refuse_chap = 0;
00511       break;
00512   }
00513 
00514   if(user) {
00515     strncpy(ppp_settings.user, user, sizeof(ppp_settings.user)-1);
00516     ppp_settings.user[sizeof(ppp_settings.user)-1] = '\0';
00517   } else {
00518     ppp_settings.user[0] = '\0';
00519   }
00520 
00521   if(passwd) {
00522     strncpy(ppp_settings.passwd, passwd, sizeof(ppp_settings.passwd)-1);
00523     ppp_settings.passwd[sizeof(ppp_settings.passwd)-1] = '\0';
00524   } else {
00525     ppp_settings.passwd[0] = '\0';
00526   }
00527 }
00528 
00529 #if PPPOS_SUPPORT
00530 /** Open a new PPP connection using the given I/O device.
00531  * This initializes the PPP control block but does not
00532  * attempt to negotiate the LCP session.  If this port
00533  * connects to a modem, the modem connection must be
00534  * established before calling this.
00535  * Return a new PPP connection descriptor on success or
00536  * an error code (negative) on failure.
00537  *
00538  * pppOpen() is directly defined to this function.
00539  */
00540 int
00541 pppOverSerialOpen(sio_fd_t fd, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx)
00542 {
00543   PPPControl *pc;
00544   int pd;
00545 
00546   if (linkStatusCB == NULL) {
00547     /* PPP is single-threaded: without a callback,
00548      * there is no way to know when the link is up. */
00549     return PPPERR_PARAM;
00550   }
00551 
00552   /* Find a free PPP session descriptor. */
00553   for (pd = 0; pd < NUM_PPP && pppControl[pd].openFlag != 0; pd++);
00554 
00555   if (pd >= NUM_PPP) {
00556     pd = PPPERR_OPEN;
00557   } else {
00558     pc = &pppControl[pd];
00559     /* @todo: is this correct or do I overwrite something? */
00560     memset(pc, 0, sizeof(PPPControl));
00561     pc->rx.pd = pd;
00562     pc->rx.fd = fd;
00563 
00564     pc->openFlag = 1;
00565     pc->fd = fd;
00566 
00567 #if VJ_SUPPORT
00568     vj_compress_init(&pc->vjComp);
00569 #endif /* VJ_SUPPORT */
00570 
00571     /* 
00572      * Default the in and out accm so that escape and flag characters
00573      * are always escaped. 
00574      */
00575     pc->rx.inACCM[15] = 0x60; /* no need to protect since RX is not running */
00576     pc->outACCM[15] = 0x60;
00577 
00578     pc->linkStatusCB = linkStatusCB;
00579     pc->linkStatusCtx = linkStatusCtx;
00580 
00581     /*
00582      * Start the connection and handle incoming events (packet or timeout).
00583      */
00584     PPPDEBUG(LOG_INFO, ("pppOverSerialOpen: unit %d: Connecting\n", pd));
00585     pppStart(pd);
00586 #if PPP_INPROC_OWNTHREAD
00587 #if __LWIP_ORIG
00588     sys_thread_new(PPP_THREAD_NAME, pppInputThread, (void*)&pc->rx, PPP_THREAD_STACKSIZE, PPP_THREAD_PRIO);
00589 #else
00590     sys_mbox_post(&pppMbox, (void*)&pc->rx);
00591 #endif
00592 #endif
00593   }
00594 
00595   return pd;
00596 }
00597 #endif /* PPPOS_SUPPORT */
00598 
00599 #if PPPOE_SUPPORT
00600 static void pppOverEthernetLinkStatusCB(int pd, int up);
00601 
00602 void
00603 pppOverEthernetClose(int pd)
00604 {
00605   PPPControl* pc = &pppControl[pd];
00606 
00607   /* *TJL* There's no lcp_deinit */
00608   lcp_close(pd, NULL);
00609 
00610   pppoe_destroy(&pc->netif);
00611 }
00612 
00613 int pppOverEthernetOpen(struct netif *ethif, const char *service_name, const char *concentrator_name, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx)
00614 {
00615   PPPControl *pc;
00616   int pd;
00617 
00618   LWIP_UNUSED_ARG(service_name);
00619   LWIP_UNUSED_ARG(concentrator_name);
00620 
00621   if (linkStatusCB == NULL) {
00622     /* PPP is single-threaded: without a callback,
00623      * there is no way to know when the link is up. */
00624     return PPPERR_PARAM;
00625   }
00626 
00627   /* Find a free PPP session descriptor. Critical region? */
00628   for (pd = 0; pd < NUM_PPP && pppControl[pd].openFlag != 0; pd++);
00629   if (pd >= NUM_PPP) {
00630     pd = PPPERR_OPEN;
00631   } else {
00632     pc = &pppControl[pd];
00633     memset(pc, 0, sizeof(PPPControl));
00634     pc->openFlag = 1;
00635     pc->ethif = ethif;
00636 
00637     pc->linkStatusCB  = linkStatusCB;
00638     pc->linkStatusCtx = linkStatusCtx;
00639 
00640     lcp_wantoptions[pd].mru = PPPOE_MAXMTU;
00641     lcp_wantoptions[pd].neg_asyncmap = 0;
00642     lcp_wantoptions[pd].neg_pcompression = 0;
00643     lcp_wantoptions[pd].neg_accompression = 0;
00644 
00645     lcp_allowoptions[pd].mru = PPPOE_MAXMTU;
00646     lcp_allowoptions[pd].neg_asyncmap = 0;
00647     lcp_allowoptions[pd].neg_pcompression = 0;
00648     lcp_allowoptions[pd].neg_accompression = 0;
00649 
00650     if(pppoe_create(ethif, pd, pppOverEthernetLinkStatusCB, &pc->pppoe_sc) != ERR_OK) {
00651       pc->openFlag = 0;
00652       return PPPERR_OPEN;
00653     }
00654 
00655     pppoe_connect(pc->pppoe_sc);
00656   }
00657 
00658   return pd;
00659 }
00660 #endif /* PPPOE_SUPPORT */
00661 
00662 
00663 /* Close a PPP connection and release the descriptor. 
00664  * Any outstanding packets in the queues are dropped.
00665  * Return 0 on success, an error code on failure. */
00666 int
00667 pppClose(int pd)
00668 {
00669   PPPControl *pc = &pppControl[pd];
00670   int st = 0;
00671 
00672   PPPDEBUG(LOG_DEBUG, ("pppClose() called\n"));
00673 
00674   /* Disconnect */
00675 #if PPPOE_SUPPORT
00676   if(pc->ethif) {
00677     PPPDEBUG(LOG_DEBUG, ("pppClose: unit %d kill_link -> pppStop\n", pd));
00678     pc->errCode = PPPERR_USER;
00679     /* This will leave us at PHASE_DEAD. */
00680     pppStop(pd);
00681   } else
00682 #endif /* PPPOE_SUPPORT */
00683   {
00684 #if PPPOS_SUPPORT
00685     PPPDEBUG(LOG_DEBUG, ("pppClose: unit %d kill_link -> pppStop\n", pd));
00686     pc->errCode = PPPERR_USER;
00687     /* This will leave us at PHASE_DEAD. */
00688     pppStop(pd);
00689     pppRecvWakeup(pd);
00690 #endif /* PPPOS_SUPPORT */
00691   }
00692 
00693   return st;
00694 }
00695 
00696 /* This function is called when carrier is lost on the PPP channel. */
00697 void
00698 pppSigHUP(int pd)
00699 {
00700   PPPDEBUG(LOG_DEBUG, ("pppSigHUP: unit %d sig_hup -> pppHupCB\n", pd));
00701   pppHup(pd);
00702 }
00703 
00704 #if PPPOS_SUPPORT
00705 static void
00706 nPut(PPPControl *pc, struct pbuf *nb)
00707 {
00708   struct pbuf *b;
00709   int c;
00710 
00711   for(b = nb; b != NULL; b = b->next) {
00712     if((c = sio_write(pc->fd, b->payload, b->len)) != b->len) {
00713       PPPDEBUG(LOG_WARNING,
00714                ("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));
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 pppifOutputOverEthernet(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 pppifOutput(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, ("pppifOutput[%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, ("pppifOutput[%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 pppifOutputOverEthernet(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, ("pppifOutput[%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, ("pppifOutput[%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              ("pppifOutput[%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, ("pppifOutput[%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  * pppifNetifInit - netif init callback
01324  */
01325 static err_t
01326 pppifNetifInit(struct netif *netif)
01327 {
01328   netif->name[0] = 'p';
01329   netif->name[1] = 'p';
01330   netif->output = pppifOutput;
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, pppifNetifInit, 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 #if !__LWIP_ORIG
01527   do
01528   {
01529   sys_arch_mbox_fetch(&pppMbox, (void**)&pcrx, 0); //Wait indefinitely
01530 #endif
01531 
01532   while (lcp_phase[pcrx->pd] != PHASE_DEAD) {
01533     count = sio_read(pcrx->fd, pcrx->rxbuf, PPPOS_RX_BUFSIZE);
01534     if(count > 0) {
01535       pppInProc(pcrx, pcrx->rxbuf, count);
01536     } else {
01537       /* nothing received, give other tasks a chance to run */
01538       sys_msleep(1);
01539     }
01540   }
01541 #if !__LWIP_ORIG
01542   } while(1); //Never terminates
01543 #endif
01544 }
01545 #endif /* PPPOS_SUPPORT && PPP_INPROC_OWNTHREAD */
01546 
01547 #if PPPOE_SUPPORT
01548 
01549 void
01550 pppOverEthernetInitFailed(int pd)
01551 {
01552   PPPControl* pc;
01553 
01554   pppHup(pd);
01555   pppStop(pd);
01556 
01557   pc = &pppControl[pd];
01558   pppoe_destroy(&pc->netif);
01559   pc->openFlag = 0;
01560 
01561   if(pc->linkStatusCB) {
01562     pc->linkStatusCB(pc->linkStatusCtx, pc->errCode ? pc->errCode : PPPERR_PROTOCOL, NULL);
01563   }
01564 }
01565 
01566 static void
01567 pppOverEthernetLinkStatusCB(int pd, int up)
01568 {
01569   if(up) {
01570     PPPDEBUG(LOG_INFO, ("pppOverEthernetLinkStatusCB: unit %d: Connecting\n", pd));
01571     pppStart(pd);
01572   } else {
01573     pppOverEthernetInitFailed(pd);
01574   }
01575 }
01576 #endif /* PPPOE_SUPPORT */
01577 
01578 struct pbuf *
01579 pppSingleBuf(struct pbuf *p)
01580 {
01581   struct pbuf *q, *b;
01582   u_char *pl;
01583 
01584   if(p->tot_len == p->len) {
01585     return p;
01586   }
01587 
01588   q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
01589   if(!q) {
01590     PPPDEBUG(LOG_ERR,
01591              ("pppSingleBuf: unable to alloc new buf (%d)\n", p->tot_len));
01592     return p; /* live dangerously */
01593   }
01594 
01595   for(b = p, pl = q->payload; b != NULL; b = b->next) {
01596     MEMCPY(pl, b->payload, b->len);
01597     pl += b->len;
01598   }
01599 
01600   pbuf_free(p);
01601 
01602   return q;
01603 }
01604 
01605 struct pppInputHeader {
01606   int unit;
01607   u16_t proto;
01608 };
01609 
01610 /*
01611  * Pass the processed input packet to the appropriate handler.
01612  * This function and all handlers run in the context of the tcpip_thread
01613  */
01614 static void
01615 pppInput(void *arg)
01616 {
01617   struct pbuf *nb = (struct pbuf *)arg;
01618   u16_t protocol;
01619   int pd;
01620 
01621   pd = ((struct pppInputHeader *)nb->payload)->unit;
01622   protocol = ((struct pppInputHeader *)nb->payload)->proto;
01623     
01624   if(pbuf_header(nb, -(int)sizeof(struct pppInputHeader))) {
01625     LWIP_ASSERT("pbuf_header failed\n", 0);
01626     goto drop;
01627   }
01628 
01629   LINK_STATS_INC(link.recv);
01630   snmp_inc_ifinucastpkts(&pppControl[pd].netif);
01631   snmp_add_ifinoctets(&pppControl[pd].netif, nb->tot_len);
01632 
01633   /*
01634    * Toss all non-LCP packets unless LCP is OPEN.
01635    * Until we get past the authentication phase, toss all packets
01636    * except LCP, LQR and authentication packets.
01637    */
01638   if((lcp_phase[pd] <= PHASE_AUTHENTICATE) && (protocol != PPP_LCP)) {
01639     if(!((protocol == PPP_LQR) || (protocol == PPP_PAP) || (protocol == PPP_CHAP)) ||
01640         (lcp_phase[pd] != PHASE_AUTHENTICATE)) {
01641       PPPDEBUG(LOG_INFO, ("pppInput: discarding proto 0x%"X16_F" in phase %d\n", protocol, lcp_phase[pd]));
01642       goto drop;
01643     }
01644   }
01645 
01646   switch(protocol) {
01647     case PPP_VJC_COMP:      /* VJ compressed TCP */
01648 #if PPPOS_SUPPORT && VJ_SUPPORT
01649       PPPDEBUG(LOG_INFO, ("pppInput[%d]: vj_comp in pbuf len=%d\n", pd, nb->len));
01650       /*
01651        * Clip off the VJ header and prepend the rebuilt TCP/IP header and
01652        * pass the result to IP.
01653        */
01654       if ((vj_uncompress_tcp(&nb, &pppControl[pd].vjComp) >= 0) && (pppControl[pd].netif.input)) {
01655         pppControl[pd].netif.input(nb, &pppControl[pd].netif);
01656         return;
01657       }
01658       /* Something's wrong so drop it. */
01659       PPPDEBUG(LOG_WARNING, ("pppInput[%d]: Dropping VJ compressed\n", pd));
01660 #else  /* PPPOS_SUPPORT && VJ_SUPPORT */
01661       /* No handler for this protocol so drop the packet. */
01662       PPPDEBUG(LOG_INFO, ("pppInput[%d]: drop VJ Comp in %d:%s\n", pd, nb->len, nb->payload));
01663 #endif /* PPPOS_SUPPORT && VJ_SUPPORT */
01664       break;
01665 
01666     case PPP_VJC_UNCOMP:    /* VJ uncompressed TCP */
01667 #if PPPOS_SUPPORT && VJ_SUPPORT
01668       PPPDEBUG(LOG_INFO, ("pppInput[%d]: vj_un in pbuf len=%d\n", pd, nb->len));
01669       /*
01670        * Process the TCP/IP header for VJ header compression and then pass
01671        * the packet to IP.
01672        */
01673       if ((vj_uncompress_uncomp(nb, &pppControl[pd].vjComp) >= 0) && pppControl[pd].netif.input) {
01674         pppControl[pd].netif.input(nb, &pppControl[pd].netif);
01675         return;
01676       }
01677       /* Something's wrong so drop it. */
01678       PPPDEBUG(LOG_WARNING, ("pppInput[%d]: Dropping VJ uncompressed\n", pd));
01679 #else  /* PPPOS_SUPPORT && VJ_SUPPORT */
01680       /* No handler for this protocol so drop the packet. */
01681       PPPDEBUG(LOG_INFO,
01682                ("pppInput[%d]: drop VJ UnComp in %d:.*H\n", 
01683                 pd, nb->len, LWIP_MIN(nb->len * 2, 40), nb->payload));
01684 #endif /* PPPOS_SUPPORT && VJ_SUPPORT */
01685       break;
01686 
01687     case PPP_IP:            /* Internet Protocol */
01688       PPPDEBUG(LOG_INFO, ("pppInput[%d]: ip in pbuf len=%d\n", pd, nb->len));
01689       if (pppControl[pd].netif.input) {
01690         pppControl[pd].netif.input(nb, &pppControl[pd].netif);
01691         return;
01692       }
01693       break;
01694 
01695     default: {
01696       struct protent *protp;
01697       int i;
01698 
01699       /*
01700        * Upcall the proper protocol input routine.
01701        */
01702       for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) {
01703         if (protp->protocol == protocol && protp->enabled_flag) {
01704           PPPDEBUG(LOG_INFO, ("pppInput[%d]: %s len=%d\n", pd, protp->name, nb->len));
01705           nb = pppSingleBuf(nb);
01706           (*protp->input)(pd, nb->payload, nb->len);
01707           PPPDEBUG(LOG_DETAIL, ("pppInput[%d]: packet processed\n", pd));
01708           goto out;
01709         }
01710       }
01711 
01712       /* No handler for this protocol so reject the packet. */
01713       PPPDEBUG(LOG_INFO, ("pppInput[%d]: rejecting unsupported proto 0x%"X16_F" len=%d\n", pd, protocol, nb->len));
01714       if (pbuf_header(nb, sizeof(protocol))) {
01715         LWIP_ASSERT("pbuf_header failed\n", 0);
01716         goto drop;
01717       }
01718 #if BYTE_ORDER == LITTLE_ENDIAN
01719       protocol = htons(protocol);
01720 #endif /* BYTE_ORDER == LITTLE_ENDIAN */
01721       SMEMCPY(nb->payload, &protocol, sizeof(protocol));
01722       lcp_sprotrej(pd, nb->payload, nb->len);
01723     }
01724     break;
01725   }
01726 
01727 drop:
01728   LINK_STATS_INC(link.drop);
01729   snmp_inc_ifindiscards(&pppControl[pd].netif);
01730 
01731 out:
01732   pbuf_free(nb);
01733   return;
01734 }
01735 
01736 #if PPPOS_SUPPORT
01737 /*
01738  * Drop the input packet.
01739  */
01740 static void
01741 pppDrop(PPPControlRx *pcrx)
01742 {
01743   if (pcrx->inHead != NULL) {
01744 #if 0
01745     PPPDEBUG(LOG_INFO, ("pppDrop: %d:%.*H\n", pcrx->inHead->len, min(60, pcrx->inHead->len * 2), pcrx->inHead->payload));
01746 #endif
01747     PPPDEBUG(LOG_INFO, ("pppDrop: pbuf len=%d, addr %p\n", pcrx->inHead->len, (void*)pcrx->inHead));
01748     if (pcrx->inTail && (pcrx->inTail != pcrx->inHead)) {
01749       pbuf_free(pcrx->inTail);
01750     }
01751     pbuf_free(pcrx->inHead);
01752     pcrx->inHead = NULL;
01753     pcrx->inTail = NULL;
01754   }
01755 #if VJ_SUPPORT
01756   vj_uncompress_err(&pppControl[pcrx->pd].vjComp);
01757 #endif /* VJ_SUPPORT */
01758 
01759   LINK_STATS_INC(link.drop);
01760   snmp_inc_ifindiscards(&pppControl[pcrx->pd].netif);
01761 }
01762 
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 
01776 /**
01777  * Process a received octet string.
01778  */
01779 static void
01780 pppInProc(PPPControlRx *pcrx, u_char *s, int l)
01781 {
01782   struct pbuf *nextNBuf;
01783   u_char curChar;
01784   u_char escaped;
01785   SYS_ARCH_DECL_PROTECT(lev);
01786 
01787   PPPDEBUG(LOG_DEBUG, ("pppInProc[%d]: got %d bytes\n", pcrx->pd, l));
01788   while (l-- > 0) {
01789     curChar = *s++;
01790 
01791     SYS_ARCH_PROTECT(lev);
01792     escaped = ESCAPE_P(pcrx->inACCM, curChar);
01793     SYS_ARCH_UNPROTECT(lev);
01794     /* Handle special characters. */
01795     if (escaped) {
01796       /* Check for escape sequences. */
01797       /* XXX Note that this does not handle an escaped 0x5d character which
01798        * would appear as an escape character.  Since this is an ASCII ']'
01799        * and there is no reason that I know of to escape it, I won't complicate
01800        * the code to handle this case. GLL */
01801       if (curChar == PPP_ESCAPE) {
01802         pcrx->inEscaped = 1;
01803       /* Check for the flag character. */
01804       } else if (curChar == PPP_FLAG) {
01805         /* If this is just an extra flag character, ignore it. */
01806         if (pcrx->inState <= PDADDRESS) {
01807           /* ignore it */;
01808         /* If we haven't received the packet header, drop what has come in. */
01809         } else if (pcrx->inState < PDDATA) {
01810           PPPDEBUG(LOG_WARNING,
01811                    ("pppInProc[%d]: Dropping incomplete packet %d\n", 
01812                     pcrx->pd, pcrx->inState));
01813           LINK_STATS_INC(link.lenerr);
01814           pppDrop(pcrx);
01815         /* If the fcs is invalid, drop the packet. */
01816         } else if (pcrx->inFCS != PPP_GOODFCS) {
01817           PPPDEBUG(LOG_INFO,
01818                    ("pppInProc[%d]: Dropping bad fcs 0x%"X16_F" proto=0x%"X16_F"\n", 
01819                     pcrx->pd, pcrx->inFCS, pcrx->inProtocol));
01820           /* Note: If you get lots of these, check for UART frame errors or try different baud rate */
01821           LINK_STATS_INC(link.chkerr);
01822           pppDrop(pcrx);
01823         /* Otherwise it's a good packet so pass it on. */
01824         } else {
01825           struct pbuf *inp;
01826           /* Trim off the checksum. */
01827           if(pcrx->inTail->len >= 2) {
01828             pcrx->inTail->len -= 2;
01829 
01830             pcrx->inTail->tot_len = pcrx->inTail->len;
01831             if (pcrx->inTail != pcrx->inHead) {
01832               pbuf_cat(pcrx->inHead, pcrx->inTail);
01833             }
01834           } else {
01835             pcrx->inTail->tot_len = pcrx->inTail->len;
01836             if (pcrx->inTail != pcrx->inHead) {
01837               pbuf_cat(pcrx->inHead, pcrx->inTail);
01838             }
01839 
01840             pbuf_realloc(pcrx->inHead, pcrx->inHead->tot_len - 2);
01841           }
01842 
01843           /* Dispatch the packet thereby consuming it. */
01844           inp = pcrx->inHead;
01845           /* Packet consumed, release our references. */
01846           pcrx->inHead = NULL;
01847           pcrx->inTail = NULL;
01848 #if PPP_INPROC_MULTITHREADED
01849           if(tcpip_callback_with_block(pppInput, inp, 0) != ERR_OK) {
01850             PPPDEBUG(LOG_ERR, ("pppInProc[%d]: tcpip_callback() failed, dropping packet\n", pcrx->pd));
01851             pbuf_free(inp);
01852             LINK_STATS_INC(link.drop);
01853             snmp_inc_ifindiscards(&pppControl[pcrx->pd].netif);
01854           }
01855 #else /* PPP_INPROC_MULTITHREADED */
01856           pppInput(inp);
01857 #endif /* PPP_INPROC_MULTITHREADED */
01858         }
01859 
01860         /* Prepare for a new packet. */
01861         pcrx->inFCS = PPP_INITFCS;
01862         pcrx->inState = PDADDRESS;
01863         pcrx->inEscaped = 0;
01864       /* Other characters are usually control characters that may have
01865        * been inserted by the physical layer so here we just drop them. */
01866       } else {
01867         PPPDEBUG(LOG_WARNING,
01868                  ("pppInProc[%d]: Dropping ACCM char <%d>\n", pcrx->pd, curChar));
01869       }
01870     /* Process other characters. */
01871     } else {
01872       /* Unencode escaped characters. */
01873       if (pcrx->inEscaped) {
01874         pcrx->inEscaped = 0;
01875         curChar ^= PPP_TRANS;
01876       }
01877 
01878       /* Process character relative to current state. */
01879       switch(pcrx->inState) {
01880         case PDIDLE:                    /* Idle state - waiting. */
01881           /* Drop the character if it's not 0xff
01882            * we would have processed a flag character above. */
01883           if (curChar != PPP_ALLSTATIONS) {
01884             break;
01885           }
01886 
01887         /* Fall through */
01888         case PDSTART:                   /* Process start flag. */
01889           /* Prepare for a new packet. */
01890           pcrx->inFCS = PPP_INITFCS;
01891 
01892         /* Fall through */
01893         case PDADDRESS:                 /* Process address field. */
01894           if (curChar == PPP_ALLSTATIONS) {
01895             pcrx->inState = PDCONTROL;
01896             break;
01897           }
01898           /* Else assume compressed address and control fields so
01899            * fall through to get the protocol... */
01900         case PDCONTROL:                 /* Process control field. */
01901           /* If we don't get a valid control code, restart. */
01902           if (curChar == PPP_UI) {
01903             pcrx->inState = PDPROTOCOL1;
01904             break;
01905           }
01906 #if 0
01907           else {
01908             PPPDEBUG(LOG_WARNING,
01909                      ("pppInProc[%d]: Invalid control <%d>\n", pcrx->pd, curChar));
01910             pcrx->inState = PDSTART;
01911           }
01912 #endif
01913         case PDPROTOCOL1:               /* Process protocol field 1. */
01914           /* If the lower bit is set, this is the end of the protocol
01915            * field. */
01916           if (curChar & 1) {
01917             pcrx->inProtocol = curChar;
01918             pcrx->inState = PDDATA;
01919           } else {
01920             pcrx->inProtocol = (u_int)curChar << 8;
01921             pcrx->inState = PDPROTOCOL2;
01922           }
01923           break;
01924         case PDPROTOCOL2:               /* Process protocol field 2. */
01925           pcrx->inProtocol |= curChar;
01926           pcrx->inState = PDDATA;
01927           break;
01928         case PDDATA:                    /* Process data byte. */
01929           /* Make space to receive processed data. */
01930           if (pcrx->inTail == NULL || pcrx->inTail->len == PBUF_POOL_BUFSIZE) {
01931             if (pcrx->inTail != NULL) {
01932               pcrx->inTail->tot_len = pcrx->inTail->len;
01933               if (pcrx->inTail != pcrx->inHead) {
01934                 pbuf_cat(pcrx->inHead, pcrx->inTail);
01935                 /* give up the inTail reference now */
01936                 pcrx->inTail = NULL;
01937               }
01938             }
01939             /* If we haven't started a packet, we need a packet header. */
01940             nextNBuf = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
01941             if (nextNBuf == NULL) {
01942               /* No free buffers.  Drop the input packet and let the
01943                * higher layers deal with it.  Continue processing
01944                * the received pbuf chain in case a new packet starts. */
01945               PPPDEBUG(LOG_ERR, ("pppInProc[%d]: NO FREE MBUFS!\n", pcrx->pd));
01946               LINK_STATS_INC(link.memerr);
01947               pppDrop(pcrx);
01948               pcrx->inState = PDSTART;  /* Wait for flag sequence. */
01949               break;
01950             }
01951             if (pcrx->inHead == NULL) {
01952               struct pppInputHeader *pih = nextNBuf->payload;
01953 
01954               pih->unit = pcrx->pd;
01955               pih->proto = pcrx->inProtocol;
01956 
01957               nextNBuf->len += sizeof(*pih);
01958 
01959               pcrx->inHead = nextNBuf;
01960             }
01961             pcrx->inTail = nextNBuf;
01962           }
01963           /* Load character into buffer. */
01964           ((u_char*)pcrx->inTail->payload)[pcrx->inTail->len++] = curChar;
01965           break;
01966       }
01967 
01968       /* update the frame check sequence number. */
01969       pcrx->inFCS = PPP_FCS(pcrx->inFCS, curChar);
01970     }
01971   } /* while (l-- > 0), all bytes processed */
01972 
01973   avRandomize();
01974 }
01975 #endif /* PPPOS_SUPPORT */
01976 
01977 #if PPPOE_SUPPORT
01978 void
01979 pppInProcOverEthernet(int pd, struct pbuf *pb)
01980 {
01981   struct pppInputHeader *pih;
01982   u16_t inProtocol;
01983 
01984   if(pb->len < sizeof(inProtocol)) {
01985     PPPDEBUG(LOG_ERR, ("pppInProcOverEthernet: too small for protocol field\n"));
01986     goto drop;
01987   }
01988 
01989   inProtocol = (((u8_t *)pb->payload)[0] << 8) | ((u8_t*)pb->payload)[1];
01990 
01991   /* make room for pppInputHeader - should not fail */
01992   if (pbuf_header(pb, sizeof(*pih) - sizeof(inProtocol)) != 0) {
01993     PPPDEBUG(LOG_ERR, ("pppInProcOverEthernet: could not allocate room for header\n"));
01994     goto drop;
01995   }
01996 
01997   pih = pb->payload;
01998 
01999   pih->unit = pd;
02000   pih->proto = inProtocol;
02001 
02002   /* Dispatch the packet thereby consuming it. */
02003   pppInput(pb);
02004   return;
02005 
02006 drop:
02007   LINK_STATS_INC(link.drop);
02008   snmp_inc_ifindiscards(&pppControl[pd].netif);
02009   pbuf_free(pb);
02010   return;
02011 }
02012 #endif /* PPPOE_SUPPORT */
02013 
02014 #if LWIP_NETIF_STATUS_CALLBACK
02015 /** Set the status callback of a PPP's netif
02016  *
02017  * @param pd The PPP descriptor returned by pppOpen()
02018  * @param status_callback pointer to the status callback function
02019  *
02020  * @see netif_set_status_callback
02021  */
02022 void
02023 ppp_set_netif_statuscallback(int pd, netif_status_callback_fn status_callback)
02024 {
02025   netif_set_status_callback(&pppControl[pd].netif, status_callback); 
02026 }
02027 #endif /* LWIP_NETIF_STATUS_CALLBACK */
02028 
02029 #if LWIP_NETIF_LINK_CALLBACK
02030 /** Set the link callback of a PPP's netif
02031  *
02032  * @param pd The PPP descriptor returned by pppOpen()
02033  * @param link_callback pointer to the link callback function
02034  *
02035  * @see netif_set_link_callback
02036  */
02037 void
02038 ppp_set_netif_linkcallback(int pd, netif_status_callback_fn link_callback)
02039 {
02040   netif_set_link_callback(&pppControl[pd].netif, link_callback); 
02041 }
02042 #endif /* LWIP_NETIF_LINK_CALLBACK */
02043 
02044 #endif /* PPP_SUPPORT */