Control a robot over the internet using UDP and a Ethernet interface.

Dependencies:   EthernetInterface Motor TextLCD mbed-rtos mbed Socket lwip-eth lwip-sys lwip

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ppp.c Source File

ppp.c

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