SAMV71 Xplained Ultra Software Package 1.4

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