1 /*****************************************************************************
2 * ppp.c - Network Point to Point Protocol program file.
3 *
4 * Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
5 * portions Copyright (c) 1997 by Global Election Systems Inc.
6 *
7 * The authors hereby grant permission to use, copy, modify, distribute,
8 * and license this software and its documentation for any purpose, provided
9 * that existing copyright notices are retained in all copies and that this
10 * notice and the following disclaimer are included verbatim in any
11 * distributions. No written agreement, license, or royalty fee is required
12 * for any of the authorized uses.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *
25 ******************************************************************************
26 * REVISION HISTORY
27 *
28 * 03-01-01 Marc Boucher <marc@mbsi.ca>
29 *   Ported to lwIP.
30 * 97-11-05 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
31 *   Original.
32 *****************************************************************************/
33 
34 /*
35  * ppp_defs.h - PPP definitions.
36  *
37  * if_pppvar.h - private structures and declarations for PPP.
38  *
39  * Copyright (c) 1994 The Australian National University.
40  * All rights reserved.
41  *
42  * Permission to use, copy, modify, and distribute this software and its
43  * documentation is hereby granted, provided that the above copyright
44  * notice appears in all copies.  This software is provided without any
45  * warranty, express or implied. The Australian National University
46  * makes no representations about the suitability of this software for
47  * any purpose.
48  *
49  * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
50  * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
51  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
52  * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
53  * OF SUCH DAMAGE.
54  *
55  * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
56  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
57  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
58  * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
59  * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
60  * OR MODIFICATIONS.
61  */
62 
63 /*
64  * if_ppp.h - Point-to-Point Protocol definitions.
65  *
66  * Copyright (c) 1989 Carnegie Mellon University.
67  * All rights reserved.
68  *
69  * Redistribution and use in source and binary forms are permitted
70  * provided that the above copyright notice and this paragraph are
71  * duplicated in all such forms and that any documentation,
72  * advertising materials, and other materials related to such
73  * distribution and use acknowledge that the software was developed
74  * by Carnegie Mellon University.  The name of the
75  * University may not be used to endorse or promote products derived
76  * from this software without specific prior written permission.
77  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
78  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
79  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
80  */
81 
82 #include "lwip/opt.h"
83 
84 #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
85 
86 #include "ppp_impl.h"
87 #include "lwip/ip.h" /* for ip_input() */
88 
89 #include "pppdebug.h"
90 
91 #include "randm.h"
92 #include "fsm.h"
93 #if PAP_SUPPORT
94 #include "pap.h"
95 #endif /* PAP_SUPPORT */
96 #if CHAP_SUPPORT
97 #include "chap.h"
98 #endif /* CHAP_SUPPORT */
99 #include "ipcp.h"
100 #include "lcp.h"
101 #include "magic.h"
102 #include "auth.h"
103 #if VJ_SUPPORT
104 #include "vj.h"
105 #endif /* VJ_SUPPORT */
106 #if PPPOE_SUPPORT
107 #include "netif/ppp_oe.h"
108 #endif /* PPPOE_SUPPORT */
109 
110 #include "lwip/tcpip.h"
111 #include "lwip/api.h"
112 #include "lwip/snmp.h"
113 
114 #include <string.h>
115 
116 /*************************/
117 /*** LOCAL DEFINITIONS ***/
118 /*************************/
119 
120 /** PPP_INPROC_MULTITHREADED==1 call pppInput using tcpip_callback().
121  * Set this to 0 if pppInProc is called inside tcpip_thread or with NO_SYS==1.
122  * Default is 1 for NO_SYS==0 (multithreaded) and 0 for NO_SYS==1 (single-threaded).
123  */
124 #ifndef PPP_INPROC_MULTITHREADED
125 #define PPP_INPROC_MULTITHREADED (NO_SYS==0)
126 #endif
127 
128 /** PPP_INPROC_OWNTHREAD==1: start a dedicated RX thread per PPP session.
129  * Default is 0: call pppos_input() for received raw characters, charcater
130  * reception is up to the port */
131 #ifndef PPP_INPROC_OWNTHREAD
132 #define PPP_INPROC_OWNTHREAD      PPP_INPROC_MULTITHREADED
133 #endif
134 
135 #if PPP_INPROC_OWNTHREAD && !PPP_INPROC_MULTITHREADED
136   #error "PPP_INPROC_OWNTHREAD needs PPP_INPROC_MULTITHREADED==1"
137 #endif
138 
139 /*
140  * The basic PPP frame.
141  */
142 #define PPP_ADDRESS(p)  (((u_char *)(p))[0])
143 #define PPP_CONTROL(p)  (((u_char *)(p))[1])
144 #define PPP_PROTOCOL(p) ((((u_char *)(p))[2] << 8) + ((u_char *)(p))[3])
145 
146 /* PPP packet parser states.  Current state indicates operation yet to be
147  * completed. */
148 typedef enum {
149   PDIDLE = 0,  /* Idle state - waiting. */
150   PDSTART,     /* Process start flag. */
151   PDADDRESS,   /* Process address field. */
152   PDCONTROL,   /* Process control field. */
153   PDPROTOCOL1, /* Process protocol field 1. */
154   PDPROTOCOL2, /* Process protocol field 2. */
155   PDDATA       /* Process data byte. */
156 } PPPDevStates;
157 
158 #define ESCAPE_P(accm, c) ((accm)[(c) >> 3] & pppACCMMask[c & 0x07])
159 
160 /************************/
161 /*** LOCAL DATA TYPES ***/
162 /************************/
163 
164 /** RX buffer size: this may be configured smaller! */
165 #ifndef PPPOS_RX_BUFSIZE
166 #define PPPOS_RX_BUFSIZE    (PPP_MRU + PPP_HDRLEN)
167 #endif
168 
169 typedef struct PPPControlRx_s {
170   /** unit number / ppp descriptor */
171   int pd;
172   /** the rx file descriptor */
173   sio_fd_t fd;
174   /** receive buffer - encoded data is stored here */
175 #if PPP_INPROC_OWNTHREAD
176   u_char rxbuf[PPPOS_RX_BUFSIZE];
177 #endif /* PPP_INPROC_OWNTHREAD */
178 
179   /* The input packet. */
180   struct pbuf *inHead, *inTail;
181 
182 #if PPPOS_SUPPORT
183   u16_t inProtocol;             /* The input protocol code. */
184   u16_t inFCS;                  /* Input Frame Check Sequence value. */
185 #endif /* PPPOS_SUPPORT */
186   PPPDevStates inState;         /* The input process state. */
187   char inEscaped;               /* Escape next character. */
188   ext_accm inACCM;              /* Async-Ctl-Char-Map for input. */
189 } PPPControlRx;
190 
191 /*
192  * PPP interface control block.
193  */
194 typedef struct PPPControl_s {
195   PPPControlRx rx;
196   char openFlag;                /* True when in use. */
197 #if PPPOE_SUPPORT
198   struct netif *ethif;
199   struct pppoe_softc *pppoe_sc;
200 #endif /* PPPOE_SUPPORT */
201   int  if_up;                   /* True when the interface is up. */
202   int  errCode;                 /* Code indicating why interface is down. */
203 #if PPPOS_SUPPORT
204   sio_fd_t fd;                  /* File device ID of port. */
205 #endif /* PPPOS_SUPPORT */
206   u16_t mtu;                    /* Peer's mru */
207   int  pcomp;                   /* Does peer accept protocol compression? */
208   int  accomp;                  /* Does peer accept addr/ctl compression? */
209   u_long lastXMit;              /* Time of last transmission. */
210   ext_accm outACCM;             /* Async-Ctl-Char-Map for output. */
211 #if PPPOS_SUPPORT && VJ_SUPPORT
212   int  vjEnabled;               /* Flag indicating VJ compression enabled. */
213   struct vjcompress vjComp;     /* Van Jacobson compression header. */
214 #endif /* PPPOS_SUPPORT && VJ_SUPPORT */
215 
216   struct netif netif;
217 
218   struct ppp_addrs addrs;
219 
220   void (*linkStatusCB)(void *ctx, int errCode, void *arg);
221   void *linkStatusCtx;
222 
223 } PPPControl;
224 
225 
226 /*
227  * Ioctl definitions.
228  */
229 
230 struct npioctl {
231   int         protocol; /* PPP procotol, e.g. PPP_IP */
232   enum NPmode mode;
233 };
234 
235 
236 
237 /***********************************/
238 /*** LOCAL FUNCTION DECLARATIONS ***/
239 /***********************************/
240 #if PPPOS_SUPPORT
241 #if PPP_INPROC_OWNTHREAD
242 static void pppInputThread(void *arg);
243 #endif /* PPP_INPROC_OWNTHREAD */
244 static void pppDrop(PPPControlRx *pcrx);
245 static void pppInProc(PPPControlRx *pcrx, u_char *s, int l);
246 static void pppFreeCurrentInputPacket(PPPControlRx *pcrx);
247 #endif /* PPPOS_SUPPORT */
248 
249 
250 /******************************/
251 /*** PUBLIC DATA STRUCTURES ***/
252 /******************************/
253 u_long subnetMask;
254 
255 static PPPControl pppControl[NUM_PPP]; /* The PPP interface control blocks. */
256 
257 /*
258  * PPP Data Link Layer "protocol" table.
259  * One entry per supported protocol.
260  * The last entry must be NULL.
261  */
262 struct protent *ppp_protocols[] = {
263   &lcp_protent,
264 #if PAP_SUPPORT
265   &pap_protent,
266 #endif /* PAP_SUPPORT */
267 #if CHAP_SUPPORT
268   &chap_protent,
269 #endif /* CHAP_SUPPORT */
270 #if CBCP_SUPPORT
271   &cbcp_protent,
272 #endif /* CBCP_SUPPORT */
273   &ipcp_protent,
274 #if CCP_SUPPORT
275   &ccp_protent,
276 #endif /* CCP_SUPPORT */
277   NULL
278 };
279 
280 
281 /*
282  * Buffers for outgoing packets.  This must be accessed only from the appropriate
283  * PPP task so that it doesn't need to be protected to avoid collisions.
284  */
285 u_char outpacket_buf[NUM_PPP][PPP_MRU+PPP_HDRLEN];
286 
287 
288 /*****************************/
289 /*** LOCAL DATA STRUCTURES ***/
290 /*****************************/
291 
292 #if PPPOS_SUPPORT
293 /*
294  * FCS lookup table as calculated by genfcstab.
295  * @todo: smaller, slower implementation for lower memory footprint?
296  */
297 static const u_short fcstab[256] = {
298   0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
299   0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
300   0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
301   0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
302   0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
303   0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
304   0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
305   0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
306   0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
307   0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
308   0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
309   0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
310   0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
311   0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
312   0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
313   0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
314   0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
315   0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
316   0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
317   0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
318   0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
319   0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
320   0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
321   0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
322   0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
323   0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
324   0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
325   0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
326   0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
327   0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
328   0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
329   0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
330 };
331 
332 /* PPP's Asynchronous-Control-Character-Map.  The mask array is used
333  * to select the specific bit for a character. */
334 static u_char pppACCMMask[] = {
335   0x01,
336   0x02,
337   0x04,
338   0x08,
339   0x10,
340   0x20,
341   0x40,
342   0x80
343 };
344 
345 #if PPP_INPROC_OWNTHREAD
346 /** Wake up the task blocked in reading from serial line (if any) */
347 static void
348 pppRecvWakeup(int pd)
349 {
350   PPPDEBUG(LOG_DEBUG, ("pppRecvWakeup: unit %d\n", pd));
351   if (pppControl[pd].openFlag != 0) {
352     sio_read_abort(pppControl[pd].fd);
353   }
354 }
355 #endif /* PPP_INPROC_OWNTHREAD */
356 #endif /* PPPOS_SUPPORT */
357 
358 void
359 pppLinkTerminated(int pd)
360 {
361   PPPDEBUG(LOG_DEBUG, ("pppLinkTerminated: unit %d\n", pd));
362 
363 #if PPPOE_SUPPORT
364   if (pppControl[pd].ethif) {
365     pppoe_disconnect(pppControl[pd].pppoe_sc);
366   } else
367 #endif /* PPPOE_SUPPORT */
368   {
369 #if PPPOS_SUPPORT
370     PPPControl* pc;
371 #if PPP_INPROC_OWNTHREAD
372     pppRecvWakeup(pd);
373 #endif /* PPP_INPROC_OWNTHREAD */
374     pc = &pppControl[pd];
375 
376     PPPDEBUG(LOG_DEBUG, ("pppLinkTerminated: unit %d: linkStatusCB=%p errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));
377     if (pc->linkStatusCB) {
378       pc->linkStatusCB(pc->linkStatusCtx, pc->errCode ? pc->errCode : PPPERR_PROTOCOL, NULL);
379     }
380 
381     pc->openFlag = 0;/**/
382 #endif /* PPPOS_SUPPORT */
383   }
384   PPPDEBUG(LOG_DEBUG, ("pppLinkTerminated: finished.\n"));
385 }
386 
387 void
388 pppLinkDown(int pd)
389 {
390   PPPDEBUG(LOG_DEBUG, ("pppLinkDown: unit %d\n", pd));
391 
392 #if PPPOE_SUPPORT
393   if (pppControl[pd].ethif) {
394     pppoe_disconnect(pppControl[pd].pppoe_sc);
395   } else
396 #endif /* PPPOE_SUPPORT */
397   {
398 #if PPPOS_SUPPORT && PPP_INPROC_OWNTHREAD
399     pppRecvWakeup(pd);
400 #endif /* PPPOS_SUPPORT && PPP_INPROC_OWNTHREAD*/
401   }
402 }
403 
404 /** Initiate LCP open request */
405 static void
406 pppStart(int pd)
407 {
408   PPPDEBUG(LOG_DEBUG, ("pppStart: unit %d\n", pd));
409   lcp_lowerup(pd);
410   lcp_open(pd); /* Start protocol */
411   PPPDEBUG(LOG_DEBUG, ("pppStart: finished\n"));
412 }
413 
414 /** LCP close request */
415 static void
416 pppStop(int pd)
417 {
418   PPPDEBUG(LOG_DEBUG, ("pppStop: unit %d\n", pd));
419   lcp_close(pd, "User request");
420 }
421 
422 /** Called when carrier/link is lost */
423 static void
424 pppHup(int pd)
425 {
426   PPPDEBUG(LOG_DEBUG, ("pppHupCB: unit %d\n", pd));
427   lcp_lowerdown(pd);
428   link_terminated(pd);
429 }
430 
431 /***********************************/
432 /*** PUBLIC FUNCTION DEFINITIONS ***/
433 /***********************************/
434 /* Initialize the PPP subsystem. */
435 
436 struct ppp_settings ppp_settings;
437 
438 void
439 pppInit(void)
440 {
441   struct protent *protp;
442   int i, j;
443 
444   memset(&ppp_settings, 0, sizeof(ppp_settings));
445   ppp_settings.usepeerdns = 1;
446   pppSetAuth(PPPAUTHTYPE_NONE, NULL, NULL);
447 
448   magicInit();
449 
450   subnetMask = PP_HTONL(0xffffff00UL);
451 
452   for (i = 0; i < NUM_PPP; i++) {
453     /* Initialize each protocol to the standard option set. */
454     for (j = 0; (protp = ppp_protocols[j]) != NULL; ++j) {
455       (*protp->init)(i);
456     }
457   }
458 }
459 
460 void
461 pppSetAuth(enum pppAuthType authType, const char *user, const char *passwd)
462 {
463   switch(authType) {
464     case PPPAUTHTYPE_NONE:
465     default:
466 #ifdef LWIP_PPP_STRICT_PAP_REJECT
467       ppp_settings.refuse_pap = 1;
468 #else  /* LWIP_PPP_STRICT_PAP_REJECT */
469       /* some providers request pap and accept an empty login/pw */
470       ppp_settings.refuse_pap = 0;
471 #endif /* LWIP_PPP_STRICT_PAP_REJECT */
472       ppp_settings.refuse_chap = 1;
473       break;
474 
475     case PPPAUTHTYPE_ANY:
476       /* Warning: Using PPPAUTHTYPE_ANY might have security consequences.
477        * RFC 1994 says:
478        *
479        * In practice, within or associated with each PPP server, there is a
480        * database which associates "user" names with authentication
481        * information ("secrets").  It is not anticipated that a particular
482        * named user would be authenticated by multiple methods.  This would
483        * make the user vulnerable to attacks which negotiate the least secure
484        * method from among a set (such as PAP rather than CHAP).  If the same
485        * secret was used, PAP would reveal the secret to be used later with
486        * CHAP.
487        *
488        * Instead, for each user name there should be an indication of exactly
489        * one method used to authenticate that user name.  If a user needs to
490        * make use of different authentication methods under different
491        * circumstances, then distinct user names SHOULD be employed, each of
492        * which identifies exactly one authentication method.
493        *
494        */
495       ppp_settings.refuse_pap = 0;
496       ppp_settings.refuse_chap = 0;
497       break;
498 
499     case PPPAUTHTYPE_PAP:
500       ppp_settings.refuse_pap = 0;
501       ppp_settings.refuse_chap = 1;
502       break;
503 
504     case PPPAUTHTYPE_CHAP:
505       ppp_settings.refuse_pap = 1;
506       ppp_settings.refuse_chap = 0;
507       break;
508   }
509 
510   if(user) {
511     strncpy(ppp_settings.user, user, sizeof(ppp_settings.user)-1);
512     ppp_settings.user[sizeof(ppp_settings.user)-1] = '\0';
513   } else {
514     ppp_settings.user[0] = '\0';
515   }
516 
517   if(passwd) {
518     strncpy(ppp_settings.passwd, passwd, sizeof(ppp_settings.passwd)-1);
519     ppp_settings.passwd[sizeof(ppp_settings.passwd)-1] = '\0';
520   } else {
521     ppp_settings.passwd[0] = '\0';
522   }
523 }
524 
525 #if PPPOS_SUPPORT
526 /** Open a new PPP connection using the given I/O device.
527  * This initializes the PPP control block but does not
528  * attempt to negotiate the LCP session.  If this port
529  * connects to a modem, the modem connection must be
530  * established before calling this.
531  * Return a new PPP connection descriptor on success or
532  * an error code (negative) on failure.
533  *
534  * pppOpen() is directly defined to this function.
535  */
536 int
537 pppOverSerialOpen(sio_fd_t fd, pppLinkStatusCB_fn linkStatusCB, void *linkStatusCtx)
538 {
539   PPPControl *pc;
540   int pd;
541 
542   if (linkStatusCB == NULL) {
543     /* PPP is single-threaded: without a callback,
544      * there is no way to know when the link is up. */
545     return PPPERR_PARAM;
546   }
547 
548   /* Find a free PPP session descriptor. */
549   for (pd = 0; pd < NUM_PPP && pppControl[pd].openFlag != 0; pd++);
550 
551   if (pd >= NUM_PPP) {
552     pd = PPPERR_OPEN;
553   } else {
554     pc = &pppControl[pd];
555     /* input pbuf left over from last session? */
556     pppFreeCurrentInputPacket(&pc->rx);
557     /* @todo: is this correct or do I overwrite something? */
558     memset(pc, 0, sizeof(PPPControl));
559     pc->rx.pd = pd;
560     pc->rx.fd = fd;
561 
562     pc->openFlag = 1;
563     pc->fd = fd;
564 
565 #if VJ_SUPPORT
566     vj_compress_init(&pc->vjComp);
567 #endif /* VJ_SUPPORT */
568 
569     /*
570      * Default the in and out accm so that escape and flag characters
571      * are always escaped.
572      */
573     pc->rx.inACCM[15] = 0x60; /* no need to protect since RX is not running */
574     pc->outACCM[15] = 0x60;
575 
576     pc->linkStatusCB = linkStatusCB;
577     pc->linkStatusCtx = linkStatusCtx;
578 
579     /*
580      * Start the connection and handle incoming events (packet or timeout).
581      */
582     PPPDEBUG(LOG_INFO, ("pppOverSerialOpen: unit %d: Connecting\n", pd));
583     pppStart(pd);
584 #if PPP_INPROC_OWNTHREAD
585     sys_thread_new(PPP_THREAD_NAME, pppInputThread, (void*)&pc->rx, PPP_THREAD_STACKSIZE, PPP_THREAD_PRIO);
586 #endif /* PPP_INPROC_OWNTHREAD */
587   }
588 
589   return pd;
590 }
591 #endif /* PPPOS_SUPPORT */
592 
593 #if PPPOE_SUPPORT
594 static void pppOverEthernetLinkStatusCB(int pd, int up);
595 
596 void
597 pppOverEthernetClose(int pd)
598 {
599   PPPControl* pc = &pppControl[pd];
600 
601   /* *TJL* There's no lcp_deinit */
602   lcp_close(pd, NULL);
603 
604   pppoe_destroy(&pc->netif);
605 }
606 
607 int pppOverEthernetOpen(struct netif *ethif, const char *service_name, const char *concentrator_name,
608                         pppLinkStatusCB_fn linkStatusCB, void *linkStatusCtx)
609 {
610   PPPControl *pc;
611   int pd;
612 
613   LWIP_UNUSED_ARG(service_name);
614   LWIP_UNUSED_ARG(concentrator_name);
615 
616   if (linkStatusCB == NULL) {
617     /* PPP is single-threaded: without a callback,
618      * there is no way to know when the link is up. */
619     return PPPERR_PARAM;
620   }
621 
622   /* Find a free PPP session descriptor. Critical region? */
623   for (pd = 0; pd < NUM_PPP && pppControl[pd].openFlag != 0; pd++);
624   if (pd >= NUM_PPP) {
625     pd = PPPERR_OPEN;
626   } else {
627     pc = &pppControl[pd];
628     memset(pc, 0, sizeof(PPPControl));
629     pc->openFlag = 1;
630     pc->ethif = ethif;
631 
632     pc->linkStatusCB  = linkStatusCB;
633     pc->linkStatusCtx = linkStatusCtx;
634 
635     lcp_wantoptions[pd].mru = PPPOE_MAXMTU;
636     lcp_wantoptions[pd].neg_asyncmap = 0;
637     lcp_wantoptions[pd].neg_pcompression = 0;
638     lcp_wantoptions[pd].neg_accompression = 0;
639 
640     lcp_allowoptions[pd].mru = PPPOE_MAXMTU;
641     lcp_allowoptions[pd].neg_asyncmap = 0;
642     lcp_allowoptions[pd].neg_pcompression = 0;
643     lcp_allowoptions[pd].neg_accompression = 0;
644 
645     if(pppoe_create(ethif, pd, pppOverEthernetLinkStatusCB, &pc->pppoe_sc) != ERR_OK) {
646       pc->openFlag = 0;
647       return PPPERR_OPEN;
648     }
649 
650     pppoe_connect(pc->pppoe_sc);
651   }
652 
653   return pd;
654 }
655 #endif /* PPPOE_SUPPORT */
656 
657 
658 /* Close a PPP connection and release the descriptor.
659  * Any outstanding packets in the queues are dropped.
660  * Return 0 on success, an error code on failure. */
661 int
662 pppClose(int pd)
663 {
664   PPPControl *pc = &pppControl[pd];
665   int st = 0;
666 
667   PPPDEBUG(LOG_DEBUG, ("pppClose() called\n"));
668 
669   /* Disconnect */
670 #if PPPOE_SUPPORT
671   if(pc->ethif) {
672     PPPDEBUG(LOG_DEBUG, ("pppClose: unit %d kill_link -> pppStop\n", pd));
673     pc->errCode = PPPERR_USER;
674     /* This will leave us at PHASE_DEAD. */
675     pppStop(pd);
676   } else
677 #endif /* PPPOE_SUPPORT */
678   {
679 #if PPPOS_SUPPORT
680     PPPDEBUG(LOG_DEBUG, ("pppClose: unit %d kill_link -> pppStop\n", pd));
681     pc->errCode = PPPERR_USER;
682     /* This will leave us at PHASE_DEAD. */
683     pppStop(pd);
684 #if PPP_INPROC_OWNTHREAD
685     pppRecvWakeup(pd);
686 #endif /* PPP_INPROC_OWNTHREAD */
687 #endif /* PPPOS_SUPPORT */
688   }
689 
690   return st;
691 }
692 
693 /* This function is called when carrier is lost on the PPP channel. */
694 void
695 pppSigHUP(int pd)
696 {
697   PPPDEBUG(LOG_DEBUG, ("pppSigHUP: unit %d sig_hup -> pppHupCB\n", pd));
698   pppHup(pd);
699 }
700 
701 #if PPPOS_SUPPORT
702 static void
703 nPut(PPPControl *pc, struct pbuf *nb)
704 {
705   struct pbuf *b;
706   int c;
707 
708   for(b = nb; b != NULL; b = b->next) {
709     if((c = sio_write(pc->fd, b->payload, b->len)) != b->len) {
710       PPPDEBUG(LOG_WARNING,
711                ("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));
712       LINK_STATS_INC(link.err);
713       pc->lastXMit = 0; /* prepend PPP_FLAG to next packet */
714       snmp_inc_ifoutdiscards(&pc->netif);
715       pbuf_free(nb);
716       return;
717     }
718   }
719 
720   snmp_add_ifoutoctets(&pc->netif, nb->tot_len);
721   snmp_inc_ifoutucastpkts(&pc->netif);
722   pbuf_free(nb);
723   LINK_STATS_INC(link.xmit);
724 }
725 
726 /*
727  * pppAppend - append given character to end of given pbuf.  If outACCM
728  * is not NULL and the character needs to be escaped, do so.
729  * If pbuf is full, append another.
730  * Return the current pbuf.
731  */
732 static struct pbuf *
733 pppAppend(u_char c, struct pbuf *nb, ext_accm *outACCM)
734 {
735   struct pbuf *tb = nb;
736 
737   /* Make sure there is room for the character and an escape code.
738    * Sure we don't quite fill the buffer if the character doesn't
739    * get escaped but is one character worth complicating this? */
740   /* Note: We assume no packet header. */
741   if (nb && (PBUF_POOL_BUFSIZE - nb->len) < 2) {
742     tb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
743     if (tb) {
744       nb->next = tb;
745     } else {
746       LINK_STATS_INC(link.memerr);
747     }
748     nb = tb;
749   }
750 
751   if (nb) {
752     if (outACCM && ESCAPE_P(*outACCM, c)) {
753       *((u_char*)nb->payload + nb->len++) = PPP_ESCAPE;
754       *((u_char*)nb->payload + nb->len++) = c ^ PPP_TRANS;
755     } else {
756       *((u_char*)nb->payload + nb->len++) = c;
757     }
758   }
759 
760   return tb;
761 }
762 #endif /* PPPOS_SUPPORT */
763 
764 #if PPPOE_SUPPORT
765 static err_t
766 pppifOutputOverEthernet(int pd, struct pbuf *p)
767 {
768   PPPControl *pc = &pppControl[pd];
769   struct pbuf *pb;
770   u_short protocol = PPP_IP;
771   int i=0;
772   u16_t tot_len;
773 
774   /* @todo: try to use pbuf_header() here! */
775   pb = pbuf_alloc(PBUF_LINK, PPPOE_HDRLEN + sizeof(protocol), PBUF_RAM);
776   if(!pb) {
777     LINK_STATS_INC(link.memerr);
778     LINK_STATS_INC(link.proterr);
779     snmp_inc_ifoutdiscards(&pc->netif);
780     return ERR_MEM;
781   }
782 
783   pbuf_header(pb, -(s16_t)PPPOE_HDRLEN);
784 
785   pc->lastXMit = sys_jiffies();
786 
787   if (!pc->pcomp || protocol > 0xFF) {
788     *((u_char*)pb->payload + i++) = (protocol >> 8) & 0xFF;
789   }
790   *((u_char*)pb->payload + i) = protocol & 0xFF;
791 
792   pbuf_chain(pb, p);
793   tot_len = pb->tot_len;
794 
795   if(pppoe_xmit(pc->pppoe_sc, pb) != ERR_OK) {
796     LINK_STATS_INC(link.err);
797     snmp_inc_ifoutdiscards(&pc->netif);
798     return PPPERR_DEVICE;
799   }
800 
801   snmp_add_ifoutoctets(&pc->netif, tot_len);
802   snmp_inc_ifoutucastpkts(&pc->netif);
803   LINK_STATS_INC(link.xmit);
804   return ERR_OK;
805 }
806 #endif /* PPPOE_SUPPORT */
807 
808 /* Send a packet on the given connection. */
809 static err_t
810 pppifOutput(struct netif *netif, struct pbuf *pb, ip_addr_t *ipaddr)
811 {
812   int pd = (int)(size_t)netif->state;
813   PPPControl *pc = &pppControl[pd];
814 #if PPPOS_SUPPORT
815   u_short protocol = PPP_IP;
816   u_int fcsOut = PPP_INITFCS;
817   struct pbuf *headMB = NULL, *tailMB = NULL, *p;
818   u_char c;
819 #endif /* PPPOS_SUPPORT */
820 
821   LWIP_UNUSED_ARG(ipaddr);
822 
823   /* Validate parameters. */
824   /* We let any protocol value go through - it can't hurt us
825    * and the peer will just drop it if it's not accepting it. */
826   if (pd < 0 || pd >= NUM_PPP || !pc->openFlag || !pb) {
827     PPPDEBUG(LOG_WARNING, ("pppifOutput[%d]: bad parms prot=%d pb=%p\n",
828               pd, PPP_IP, pb));
829     LINK_STATS_INC(link.opterr);
830     LINK_STATS_INC(link.drop);
831     snmp_inc_ifoutdiscards(netif);
832     return ERR_ARG;
833   }
834 
835   /* Check that the link is up. */
836   if (lcp_phase[pd] == PHASE_DEAD) {
837     PPPDEBUG(LOG_ERR, ("pppifOutput[%d]: link not up\n", pd));
838     LINK_STATS_INC(link.rterr);
839     LINK_STATS_INC(link.drop);
840     snmp_inc_ifoutdiscards(netif);
841     return ERR_RTE;
842   }
843 
844 #if PPPOE_SUPPORT
845   if(pc->ethif) {
846     return pppifOutputOverEthernet(pd, pb);
847   }
848 #endif /* PPPOE_SUPPORT */
849 
850 #if PPPOS_SUPPORT
851   /* Grab an output buffer. */
852   headMB = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
853   if (headMB == NULL) {
854     PPPDEBUG(LOG_WARNING, ("pppifOutput[%d]: first alloc fail\n", pd));
855     LINK_STATS_INC(link.memerr);
856     LINK_STATS_INC(link.drop);
857     snmp_inc_ifoutdiscards(netif);
858     return ERR_MEM;
859   }
860 
861 #if VJ_SUPPORT
862   /*
863    * Attempt Van Jacobson header compression if VJ is configured and
864    * this is an IP packet.
865    */
866   if (protocol == PPP_IP && pc->vjEnabled) {
867     switch (vj_compress_tcp(&pc->vjComp, pb)) {
868       case TYPE_IP:
869         /* No change...
870            protocol = PPP_IP_PROTOCOL; */
871         break;
872       case TYPE_COMPRESSED_TCP:
873         protocol = PPP_VJC_COMP;
874         break;
875       case TYPE_UNCOMPRESSED_TCP:
876         protocol = PPP_VJC_UNCOMP;
877         break;
878       default:
879         PPPDEBUG(LOG_WARNING, ("pppifOutput[%d]: bad IP packet\n", pd));
880         LINK_STATS_INC(link.proterr);
881         LINK_STATS_INC(link.drop);
882         snmp_inc_ifoutdiscards(netif);
883         pbuf_free(headMB);
884         return ERR_VAL;
885     }
886   }
887 #endif /* VJ_SUPPORT */
888 
889   tailMB = headMB;
890 
891   /* Build the PPP header. */
892   if ((sys_jiffies() - pc->lastXMit) >= PPP_MAXIDLEFLAG) {
893     tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
894   }
895 
896   pc->lastXMit = sys_jiffies();
897   if (!pc->accomp) {
898     fcsOut = PPP_FCS(fcsOut, PPP_ALLSTATIONS);
899     tailMB = pppAppend(PPP_ALLSTATIONS, tailMB, &pc->outACCM);
900     fcsOut = PPP_FCS(fcsOut, PPP_UI);
901     tailMB = pppAppend(PPP_UI, tailMB, &pc->outACCM);
902   }
903   if (!pc->pcomp || protocol > 0xFF) {
904     c = (protocol >> 8) & 0xFF;
905     fcsOut = PPP_FCS(fcsOut, c);
906     tailMB = pppAppend(c, tailMB, &pc->outACCM);
907   }
908   c = protocol & 0xFF;
909   fcsOut = PPP_FCS(fcsOut, c);
910   tailMB = pppAppend(c, tailMB, &pc->outACCM);
911 
912   /* Load packet. */
913   for(p = pb; p; p = p->next) {
914     int n;
915     u_char *sPtr;
916 
917     sPtr = (u_char*)p->payload;
918     n = p->len;
919     while (n-- > 0) {
920       c = *sPtr++;
921 
922       /* Update FCS before checking for special characters. */
923       fcsOut = PPP_FCS(fcsOut, c);
924 
925       /* Copy to output buffer escaping special characters. */
926       tailMB = pppAppend(c, tailMB, &pc->outACCM);
927     }
928   }
929 
930   /* Add FCS and trailing flag. */
931   c = ~fcsOut & 0xFF;
932   tailMB = pppAppend(c, tailMB, &pc->outACCM);
933   c = (~fcsOut >> 8) & 0xFF;
934   tailMB = pppAppend(c, tailMB, &pc->outACCM);
935   tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
936 
937   /* If we failed to complete the packet, throw it away. */
938   if (!tailMB) {
939     PPPDEBUG(LOG_WARNING,
940              ("pppifOutput[%d]: Alloc err - dropping proto=%d\n",
941               pd, protocol));
942     pbuf_free(headMB);
943     LINK_STATS_INC(link.memerr);
944     LINK_STATS_INC(link.drop);
945     snmp_inc_ifoutdiscards(netif);
946     return ERR_MEM;
947   }
948 
949   /* Send it. */
950   PPPDEBUG(LOG_INFO, ("pppifOutput[%d]: proto=0x%"X16_F"\n", pd, protocol));
951 
952   nPut(pc, headMB);
953 #endif /* PPPOS_SUPPORT */
954 
955   return ERR_OK;
956 }
957 
958 /* Get and set parameters for the given connection.
959  * Return 0 on success, an error code on failure. */
960 int
961 pppIOCtl(int pd, int cmd, void *arg)
962 {
963   PPPControl *pc = &pppControl[pd];
964   int st = 0;
965 
966   if (pd < 0 || pd >= NUM_PPP) {
967     st = PPPERR_PARAM;
968   } else {
969     switch(cmd) {
970     case PPPCTLG_UPSTATUS:      /* Get the PPP up status. */
971       if (arg) {
972         *(int *)arg = (int)(pc->if_up);
973       } else {
974         st = PPPERR_PARAM;
975       }
976       break;
977     case PPPCTLS_ERRCODE:       /* Set the PPP error code. */
978       if (arg) {
979         pc->errCode = *(int *)arg;
980       } else {
981         st = PPPERR_PARAM;
982       }
983       break;
984     case PPPCTLG_ERRCODE:       /* Get the PPP error code. */
985       if (arg) {
986         *(int *)arg = (int)(pc->errCode);
987       } else {
988         st = PPPERR_PARAM;
989       }
990       break;
991 #if PPPOS_SUPPORT
992     case PPPCTLG_FD:            /* Get the fd associated with the ppp */
993       if (arg) {
994         *(sio_fd_t *)arg = pc->fd;
995       } else {
996         st = PPPERR_PARAM;
997       }
998       break;
999 #endif /* PPPOS_SUPPORT */
1000     default:
1001       st = PPPERR_PARAM;
1002       break;
1003     }
1004   }
1005 
1006   return st;
1007 }
1008 
1009 /*
1010  * Return the Maximum Transmission Unit for the given PPP connection.
1011  */
1012 u_short
1013 pppMTU(int pd)
1014 {
1015   PPPControl *pc = &pppControl[pd];
1016   u_short st;
1017 
1018   /* Validate parameters. */
1019   if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
1020     st = 0;
1021   } else {
1022     st = pc->mtu;
1023   }
1024 
1025   return st;
1026 }
1027 
1028 #if PPPOE_SUPPORT
1029 int
1030 pppWriteOverEthernet(int pd, const u_char *s, int n)
1031 {
1032   PPPControl *pc = &pppControl[pd];
1033   struct pbuf *pb;
1034 
1035   /* skip address & flags */
1036   s += 2;
1037   n -= 2;
1038 
1039   LWIP_ASSERT("PPPOE_HDRLEN + n <= 0xffff", PPPOE_HDRLEN + n <= 0xffff);
1040   pb = pbuf_alloc(PBUF_LINK, (u16_t)(PPPOE_HDRLEN + n), PBUF_RAM);
1041   if(!pb) {
1042     LINK_STATS_INC(link.memerr);
1043     LINK_STATS_INC(link.proterr);
1044     snmp_inc_ifoutdiscards(&pc->netif);
1045     return PPPERR_ALLOC;
1046   }
1047 
1048   pbuf_header(pb, -(s16_t)PPPOE_HDRLEN);
1049 
1050   pc->lastXMit = sys_jiffies();
1051 
1052   MEMCPY(pb->payload, s, n);
1053 
1054   if(pppoe_xmit(pc->pppoe_sc, pb) != ERR_OK) {
1055     LINK_STATS_INC(link.err);
1056     snmp_inc_ifoutdiscards(&pc->netif);
1057     return PPPERR_DEVICE;
1058   }
1059 
1060   snmp_add_ifoutoctets(&pc->netif, (u16_t)n);
1061   snmp_inc_ifoutucastpkts(&pc->netif);
1062   LINK_STATS_INC(link.xmit);
1063   return PPPERR_NONE;
1064 }
1065 #endif /* PPPOE_SUPPORT */
1066 
1067 /*
1068  * Write n characters to a ppp link.
1069  *  RETURN: >= 0 Number of characters written
1070  *           -1 Failed to write to device
1071  */
1072 int
1073 pppWrite(int pd, const u_char *s, int n)
1074 {
1075   PPPControl *pc = &pppControl[pd];
1076 #if PPPOS_SUPPORT
1077   u_char c;
1078   u_int fcsOut;
1079   struct pbuf *headMB, *tailMB;
1080 #endif /* PPPOS_SUPPORT */
1081 
1082 #if PPPOE_SUPPORT
1083   if(pc->ethif) {
1084     return pppWriteOverEthernet(pd, s, n);
1085   }
1086 #endif /* PPPOE_SUPPORT */
1087 
1088 #if PPPOS_SUPPORT
1089   headMB = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
1090   if (headMB == NULL) {
1091     LINK_STATS_INC(link.memerr);
1092     LINK_STATS_INC(link.proterr);
1093     snmp_inc_ifoutdiscards(&pc->netif);
1094     return PPPERR_ALLOC;
1095   }
1096 
1097   tailMB = headMB;
1098 
1099   /* If the link has been idle, we'll send a fresh flag character to
1100    * flush any noise. */
1101   if ((sys_jiffies() - pc->lastXMit) >= PPP_MAXIDLEFLAG) {
1102     tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
1103   }
1104   pc->lastXMit = sys_jiffies();
1105 
1106   fcsOut = PPP_INITFCS;
1107   /* Load output buffer. */
1108   while (n-- > 0) {
1109     c = *s++;
1110 
1111     /* Update FCS before checking for special characters. */
1112     fcsOut = PPP_FCS(fcsOut, c);
1113 
1114     /* Copy to output buffer escaping special characters. */
1115     tailMB = pppAppend(c, tailMB, &pc->outACCM);
1116   }
1117 
1118   /* Add FCS and trailing flag. */
1119   c = ~fcsOut & 0xFF;
1120   tailMB = pppAppend(c, tailMB, &pc->outACCM);
1121   c = (~fcsOut >> 8) & 0xFF;
1122   tailMB = pppAppend(c, tailMB, &pc->outACCM);
1123   tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
1124 
1125   /* If we failed to complete the packet, throw it away.
1126    * Otherwise send it. */
1127   if (!tailMB) {
1128     PPPDEBUG(LOG_WARNING,
1129              ("pppWrite[%d]: Alloc err - dropping pbuf len=%d\n", pd, headMB->len));
1130            /*"pppWrite[%d]: Alloc err - dropping %d:%.*H", pd, headMB->len, LWIP_MIN(headMB->len * 2, 40), headMB->payload)); */
1131     pbuf_free(headMB);
1132     LINK_STATS_INC(link.memerr);
1133     LINK_STATS_INC(link.proterr);
1134     snmp_inc_ifoutdiscards(&pc->netif);
1135     return PPPERR_ALLOC;
1136   }
1137 
1138   PPPDEBUG(LOG_INFO, ("pppWrite[%d]: len=%d\n", pd, headMB->len));
1139                    /* "pppWrite[%d]: %d:%.*H", pd, headMB->len, LWIP_MIN(headMB->len * 2, 40), headMB->payload)); */
1140   nPut(pc, headMB);
1141 #endif /* PPPOS_SUPPORT */
1142 
1143   return PPPERR_NONE;
1144 }
1145 
1146 /*
1147  * ppp_send_config - configure the transmit characteristics of
1148  * the ppp interface.
1149  */
1150 void
1151 ppp_send_config( int unit, u16_t mtu, u32_t asyncmap, int pcomp, int accomp)
1152 {
1153   PPPControl *pc = &pppControl[unit];
1154   int i;
1155 
1156   pc->mtu = mtu;
1157   pc->pcomp = pcomp;
1158   pc->accomp = accomp;
1159 
1160   /* Load the ACCM bits for the 32 control codes. */
1161   for (i = 0; i < 32/8; i++) {
1162     pc->outACCM[i] = (u_char)((asyncmap >> (8 * i)) & 0xFF);
1163   }
1164   PPPDEBUG(LOG_INFO, ("ppp_send_config[%d]: outACCM=%X %X %X %X\n",
1165             unit,
1166             pc->outACCM[0], pc->outACCM[1], pc->outACCM[2], pc->outACCM[3]));
1167 }
1168 
1169 
1170 /*
1171  * ppp_set_xaccm - set the extended transmit ACCM for the interface.
1172  */
1173 void
1174 ppp_set_xaccm(int unit, ext_accm *accm)
1175 {
1176   SMEMCPY(pppControl[unit].outACCM, accm, sizeof(ext_accm));
1177   PPPDEBUG(LOG_INFO, ("ppp_set_xaccm[%d]: outACCM=%X %X %X %X\n",
1178             unit,
1179             pppControl[unit].outACCM[0],
1180             pppControl[unit].outACCM[1],
1181             pppControl[unit].outACCM[2],
1182             pppControl[unit].outACCM[3]));
1183 }
1184 
1185 
1186 /*
1187  * ppp_recv_config - configure the receive-side characteristics of
1188  * the ppp interface.
1189  */
1190 void
1191 ppp_recv_config( int unit, int mru, u32_t asyncmap, int pcomp, int accomp)
1192 {
1193   PPPControl *pc = &pppControl[unit];
1194   int i;
1195   SYS_ARCH_DECL_PROTECT(lev);
1196 
1197   LWIP_UNUSED_ARG(accomp);
1198   LWIP_UNUSED_ARG(pcomp);
1199   LWIP_UNUSED_ARG(mru);
1200 
1201   /* Load the ACCM bits for the 32 control codes. */
1202   SYS_ARCH_PROTECT(lev);
1203   for (i = 0; i < 32 / 8; i++) {
1204     /* @todo: does this work? ext_accm has been modified from pppd! */
1205     pc->rx.inACCM[i] = (u_char)(asyncmap >> (i * 8));
1206   }
1207   SYS_ARCH_UNPROTECT(lev);
1208   PPPDEBUG(LOG_INFO, ("ppp_recv_config[%d]: inACCM=%X %X %X %X\n",
1209             unit,
1210             pc->rx.inACCM[0], pc->rx.inACCM[1], pc->rx.inACCM[2], pc->rx.inACCM[3]));
1211 }
1212 
1213 #if 0
1214 /*
1215  * ccp_test - ask kernel whether a given compression method
1216  * is acceptable for use.  Returns 1 if the method and parameters
1217  * are OK, 0 if the method is known but the parameters are not OK
1218  * (e.g. code size should be reduced), or -1 if the method is unknown.
1219  */
1220 int
1221 ccp_test( int unit, int opt_len,  int for_transmit, u_char *opt_ptr)
1222 {
1223   return 0; /* XXX Currently no compression. */
1224 }
1225 
1226 /*
1227  * ccp_flags_set - inform kernel about the current state of CCP.
1228  */
1229 void
1230 ccp_flags_set(int unit, int isopen, int isup)
1231 {
1232   /* XXX */
1233 }
1234 
1235 /*
1236  * ccp_fatal_error - returns 1 if decompression was disabled as a
1237  * result of an error detected after decompression of a packet,
1238  * 0 otherwise.  This is necessary because of patent nonsense.
1239  */
1240 int
1241 ccp_fatal_error(int unit)
1242 {
1243   /* XXX */
1244   return 0;
1245 }
1246 #endif
1247 
1248 /*
1249  * get_idle_time - return how long the link has been idle.
1250  */
1251 int
1252 get_idle_time(int u, struct ppp_idle *ip)
1253 {
1254   /* XXX */
1255   LWIP_UNUSED_ARG(u);
1256   LWIP_UNUSED_ARG(ip);
1257 
1258   return 0;
1259 }
1260 
1261 
1262 /*
1263  * Return user specified netmask, modified by any mask we might determine
1264  * for address `addr' (in network byte order).
1265  * Here we scan through the system's list of interfaces, looking for
1266  * any non-point-to-point interfaces which might appear to be on the same
1267  * network as `addr'.  If we find any, we OR in their netmask to the
1268  * user-specified netmask.
1269  */
1270 u32_t
1271 GetMask(u32_t addr)
1272 {
1273   u32_t mask, nmask;
1274 
1275   addr = htonl(addr);
1276   if (IP_CLASSA(addr)) { /* determine network mask for address class */
1277     nmask = IP_CLASSA_NET;
1278   } else if (IP_CLASSB(addr)) {
1279     nmask = IP_CLASSB_NET;
1280   } else {
1281     nmask = IP_CLASSC_NET;
1282   }
1283 
1284   /* class D nets are disallowed by bad_ip_adrs */
1285   mask = subnetMask | htonl(nmask);
1286 
1287   /* XXX
1288    * Scan through the system's network interfaces.
1289    * Get each netmask and OR them into our mask.
1290    */
1291 
1292   return mask;
1293 }
1294 
1295 /*
1296  * sifvjcomp - config tcp header compression
1297  */
1298 int
1299 sifvjcomp(int pd, int vjcomp, u8_t cidcomp, u8_t maxcid)
1300 {
1301 #if PPPOS_SUPPORT && VJ_SUPPORT
1302   PPPControl *pc = &pppControl[pd];
1303 
1304   pc->vjEnabled = vjcomp;
1305   pc->vjComp.compressSlot = cidcomp;
1306   pc->vjComp.maxSlotIndex = maxcid;
1307   PPPDEBUG(LOG_INFO, ("sifvjcomp: VJ compress enable=%d slot=%d max slot=%d\n",
1308             vjcomp, cidcomp, maxcid));
1309 #else /* PPPOS_SUPPORT && VJ_SUPPORT */
1310   LWIP_UNUSED_ARG(pd);
1311   LWIP_UNUSED_ARG(vjcomp);
1312   LWIP_UNUSED_ARG(cidcomp);
1313   LWIP_UNUSED_ARG(maxcid);
1314 #endif /* PPPOS_SUPPORT && VJ_SUPPORT */
1315 
1316   return 0;
1317 }
1318 
1319 /*
1320  * pppifNetifInit - netif init callback
1321  */
1322 static err_t
1323 pppifNetifInit(struct netif *netif)
1324 {
1325   netif->name[0] = 'p';
1326   netif->name[1] = 'p';
1327   netif->output = pppifOutput;
1328   netif->mtu = pppMTU((int)(size_t)netif->state);
1329   netif->flags = NETIF_FLAG_POINTTOPOINT | NETIF_FLAG_LINK_UP;
1330 #if LWIP_NETIF_HOSTNAME
1331   /* @todo: Initialize interface hostname */
1332   /* netif_set_hostname(netif, "lwip"); */
1333 #endif /* LWIP_NETIF_HOSTNAME */
1334   return ERR_OK;
1335 }
1336 
1337 
1338 /*
1339  * sifup - Config the interface up and enable IP packets to pass.
1340  */
1341 int
1342 sifup(int pd)
1343 {
1344   PPPControl *pc = &pppControl[pd];
1345   int st = 1;
1346 
1347   if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
1348     st = 0;
1349     PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd));
1350   } else {
1351     netif_remove(&pc->netif);
1352     if (netif_add(&pc->netif, &pc->addrs.our_ipaddr, &pc->addrs.netmask,
1353                   &pc->addrs.his_ipaddr, (void *)(size_t)pd, pppifNetifInit, ip_input)) {
1354       netif_set_up(&pc->netif);
1355       pc->if_up = 1;
1356       pc->errCode = PPPERR_NONE;
1357 
1358       PPPDEBUG(LOG_DEBUG, ("sifup: unit %d: linkStatusCB=%p errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));
1359       if (pc->linkStatusCB) {
1360         pc->linkStatusCB(pc->linkStatusCtx, pc->errCode, &pc->addrs);
1361       }
1362     } else {
1363       st = 0;
1364       PPPDEBUG(LOG_ERR, ("sifup[%d]: netif_add failed\n", pd));
1365     }
1366   }
1367 
1368   return st;
1369 }
1370 
1371 /*
1372  * sifnpmode - Set the mode for handling packets for a given NP.
1373  */
1374 int
1375 sifnpmode(int u, int proto, enum NPmode mode)
1376 {
1377   LWIP_UNUSED_ARG(u);
1378   LWIP_UNUSED_ARG(proto);
1379   LWIP_UNUSED_ARG(mode);
1380   return 0;
1381 }
1382 
1383 /*
1384  * sifdown - Config the interface down and disable IP.
1385  */
1386 int
1387 sifdown(int pd)
1388 {
1389   PPPControl *pc = &pppControl[pd];
1390   int st = 1;
1391 
1392   if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
1393     st = 0;
1394     PPPDEBUG(LOG_WARNING, ("sifdown[%d]: bad parms\n", pd));
1395   } else {
1396     pc->if_up = 0;
1397     /* make sure the netif status callback is called */
1398     netif_set_down(&pc->netif);
1399     netif_remove(&pc->netif);
1400     PPPDEBUG(LOG_DEBUG, ("sifdown: unit %d: linkStatusCB=%p errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));
1401     if (pc->linkStatusCB) {
1402       pc->linkStatusCB(pc->linkStatusCtx, PPPERR_CONNECT, NULL);
1403     }
1404   }
1405   return st;
1406 }
1407 
1408 /**
1409  * sifaddr - Config the interface IP addresses and netmask.
1410  * @param pd Interface unit ???
1411  * @param o Our IP address ???
1412  * @param h His IP address ???
1413  * @param m IP subnet mask ???
1414  * @param ns1 Primary DNS
1415  * @param ns2 Secondary DNS
1416  */
1417 int
1418 sifaddr( int pd, u32_t o, u32_t h, u32_t m, u32_t ns1, u32_t ns2)
1419 {
1420   PPPControl *pc = &pppControl[pd];
1421   int st = 1;
1422 
1423   if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
1424     st = 0;
1425     PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd));
1426   } else {
1427     SMEMCPY(&pc->addrs.our_ipaddr, &o, sizeof(o));
1428     SMEMCPY(&pc->addrs.his_ipaddr, &h, sizeof(h));
1429     SMEMCPY(&pc->addrs.netmask, &m, sizeof(m));
1430     SMEMCPY(&pc->addrs.dns1, &ns1, sizeof(ns1));
1431     SMEMCPY(&pc->addrs.dns2, &ns2, sizeof(ns2));
1432   }
1433   return st;
1434 }
1435 
1436 /**
1437  * cifaddr - Clear the interface IP addresses, and delete routes
1438  * through the interface if possible.
1439  * @param pd Interface unit ???
1440  * @param o Our IP address ???
1441  * @param h IP broadcast address ???
1442  */
1443 int
1444 cifaddr( int pd, u32_t o, u32_t h)
1445 {
1446   PPPControl *pc = &pppControl[pd];
1447   int st = 1;
1448 
1449   LWIP_UNUSED_ARG(o);
1450   LWIP_UNUSED_ARG(h);
1451   if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
1452     st = 0;
1453     PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd));
1454   } else {
1455     IP4_ADDR(&pc->addrs.our_ipaddr, 0,0,0,0);
1456     IP4_ADDR(&pc->addrs.his_ipaddr, 0,0,0,0);
1457     IP4_ADDR(&pc->addrs.netmask, 255,255,255,0);
1458     IP4_ADDR(&pc->addrs.dns1, 0,0,0,0);
1459     IP4_ADDR(&pc->addrs.dns2, 0,0,0,0);
1460   }
1461   return st;
1462 }
1463 
1464 /*
1465  * sifdefaultroute - assign a default route through the address given.
1466  */
1467 int
1468 sifdefaultroute(int pd, u32_t l, u32_t g)
1469 {
1470   PPPControl *pc = &pppControl[pd];
1471   int st = 1;
1472 
1473   LWIP_UNUSED_ARG(l);
1474   LWIP_UNUSED_ARG(g);
1475 
1476   if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
1477     st = 0;
1478     PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd));
1479   } else {
1480     netif_set_default(&pc->netif);
1481   }
1482 
1483   /* TODO: check how PPP handled the netMask, previously not set by ipSetDefault */
1484 
1485   return st;
1486 }
1487 
1488 /*
1489  * cifdefaultroute - delete a default route through the address given.
1490  */
1491 int
1492 cifdefaultroute(int pd, u32_t l, u32_t g)
1493 {
1494   PPPControl *pc = &pppControl[pd];
1495   int st = 1;
1496 
1497   LWIP_UNUSED_ARG(l);
1498   LWIP_UNUSED_ARG(g);
1499 
1500   if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
1501     st = 0;
1502     PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd));
1503   } else {
1504     netif_set_default(NULL);
1505   }
1506 
1507   return st;
1508 }
1509 
1510 /**********************************/
1511 /*** LOCAL FUNCTION DEFINITIONS ***/
1512 /**********************************/
1513 
1514 #if PPPOS_SUPPORT && PPP_INPROC_OWNTHREAD
1515 /* The main PPP process function.  This implements the state machine according
1516  * to section 4 of RFC 1661: The Point-To-Point Protocol. */
1517 static void
1518 pppInputThread(void *arg)
1519 {
1520   int count;
1521   PPPControlRx *pcrx = arg;
1522 
1523   while (lcp_phase[pcrx->pd] != PHASE_DEAD) {
1524     count = sio_read(pcrx->fd, pcrx->rxbuf, PPPOS_RX_BUFSIZE);
1525     if(count > 0) {
1526       pppInProc(pcrx, pcrx->rxbuf, count);
1527     } else {
1528       /* nothing received, give other tasks a chance to run */
1529       sys_msleep(1);
1530     }
1531   }
1532 }
1533 #endif /* PPPOS_SUPPORT && PPP_INPROC_OWNTHREAD */
1534 
1535 #if PPPOE_SUPPORT
1536 
1537 void
1538 pppOverEthernetInitFailed(int pd)
1539 {
1540   PPPControl* pc;
1541 
1542   pppHup(pd);
1543   pppStop(pd);
1544 
1545   pc = &pppControl[pd];
1546   pppoe_destroy(&pc->netif);
1547   pc->openFlag = 0;
1548 
1549   if(pc->linkStatusCB) {
1550     pc->linkStatusCB(pc->linkStatusCtx, pc->errCode ? pc->errCode : PPPERR_PROTOCOL, NULL);
1551   }
1552 }
1553 
1554 static void
1555 pppOverEthernetLinkStatusCB(int pd, int up)
1556 {
1557   if(up) {
1558     PPPDEBUG(LOG_INFO, ("pppOverEthernetLinkStatusCB: unit %d: Connecting\n", pd));
1559     pppStart(pd);
1560   } else {
1561     pppOverEthernetInitFailed(pd);
1562   }
1563 }
1564 #endif /* PPPOE_SUPPORT */
1565 
1566 struct pbuf *
1567 pppSingleBuf(struct pbuf *p)
1568 {
1569   struct pbuf *q, *b;
1570   u_char *pl;
1571 
1572   if(p->tot_len == p->len) {
1573     return p;
1574   }
1575 
1576   q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
1577   if(!q) {
1578     PPPDEBUG(LOG_ERR,
1579              ("pppSingleBuf: unable to alloc new buf (%d)\n", p->tot_len));
1580     return p; /* live dangerously */
1581   }
1582 
1583   for(b = p, pl = q->payload; b != NULL; b = b->next) {
1584     MEMCPY(pl, b->payload, b->len);
1585     pl += b->len;
1586   }
1587 
1588   pbuf_free(p);
1589 
1590   return q;
1591 }
1592 
1593 struct pppInputHeader {
1594   int unit;
1595   u16_t proto;
1596 };
1597 
1598 /*
1599  * Pass the processed input packet to the appropriate handler.
1600  * This function and all handlers run in the context of the tcpip_thread
1601  */
1602 static void
1603 pppInput(void *arg)
1604 {
1605   struct pbuf *nb = (struct pbuf *)arg;
1606   u16_t protocol;
1607   int pd;
1608 
1609   pd = ((struct pppInputHeader *)nb->payload)->unit;
1610   protocol = ((struct pppInputHeader *)nb->payload)->proto;
1611 
1612   if(pbuf_header(nb, -(int)sizeof(struct pppInputHeader))) {
1613     LWIP_ASSERT("pbuf_header failed\n", 0);
1614     goto drop;
1615   }
1616 
1617   LINK_STATS_INC(link.recv);
1618   snmp_inc_ifinucastpkts(&pppControl[pd].netif);
1619   snmp_add_ifinoctets(&pppControl[pd].netif, nb->tot_len);
1620 
1621   /*
1622    * Toss all non-LCP packets unless LCP is OPEN.
1623    * Until we get past the authentication phase, toss all packets
1624    * except LCP, LQR and authentication packets.
1625    */
1626   if((lcp_phase[pd] <= PHASE_AUTHENTICATE) && (protocol != PPP_LCP)) {
1627     if(!((protocol == PPP_LQR) || (protocol == PPP_PAP) || (protocol == PPP_CHAP)) ||
1628         (lcp_phase[pd] != PHASE_AUTHENTICATE)) {
1629       PPPDEBUG(LOG_INFO, ("pppInput: discarding proto 0x%"X16_F" in phase %d\n", protocol, lcp_phase[pd]));
1630       goto drop;
1631     }
1632   }
1633 
1634   switch(protocol) {
1635     case PPP_VJC_COMP:      /* VJ compressed TCP */
1636 #if PPPOS_SUPPORT && VJ_SUPPORT
1637       PPPDEBUG(LOG_INFO, ("pppInput[%d]: vj_comp in pbuf len=%d\n", pd, nb->len));
1638       /*
1639        * Clip off the VJ header and prepend the rebuilt TCP/IP header and
1640        * pass the result to IP.
1641        */
1642       if ((vj_uncompress_tcp(&nb, &pppControl[pd].vjComp) >= 0) && (pppControl[pd].netif.input)) {
1643         pppControl[pd].netif.input(nb, &pppControl[pd].netif);
1644         return;
1645       }
1646       /* Something's wrong so drop it. */
1647       PPPDEBUG(LOG_WARNING, ("pppInput[%d]: Dropping VJ compressed\n", pd));
1648 #else  /* PPPOS_SUPPORT && VJ_SUPPORT */
1649       /* No handler for this protocol so drop the packet. */
1650       PPPDEBUG(LOG_INFO, ("pppInput[%d]: drop VJ Comp in %d:%s\n", pd, nb->len, nb->payload));
1651 #endif /* PPPOS_SUPPORT && VJ_SUPPORT */
1652       break;
1653 
1654     case PPP_VJC_UNCOMP:    /* VJ uncompressed TCP */
1655 #if PPPOS_SUPPORT && VJ_SUPPORT
1656       PPPDEBUG(LOG_INFO, ("pppInput[%d]: vj_un in pbuf len=%d\n", pd, nb->len));
1657       /*
1658        * Process the TCP/IP header for VJ header compression and then pass
1659        * the packet to IP.
1660        */
1661       if ((vj_uncompress_uncomp(nb, &pppControl[pd].vjComp) >= 0) && pppControl[pd].netif.input) {
1662         pppControl[pd].netif.input(nb, &pppControl[pd].netif);
1663         return;
1664       }
1665       /* Something's wrong so drop it. */
1666       PPPDEBUG(LOG_WARNING, ("pppInput[%d]: Dropping VJ uncompressed\n", pd));
1667 #else  /* PPPOS_SUPPORT && VJ_SUPPORT */
1668       /* No handler for this protocol so drop the packet. */
1669       PPPDEBUG(LOG_INFO,
1670                ("pppInput[%d]: drop VJ UnComp in %d:.*H\n",
1671                 pd, nb->len, LWIP_MIN(nb->len * 2, 40), nb->payload));
1672 #endif /* PPPOS_SUPPORT && VJ_SUPPORT */
1673       break;
1674 
1675     case PPP_IP:            /* Internet Protocol */
1676       PPPDEBUG(LOG_INFO, ("pppInput[%d]: ip in pbuf len=%d\n", pd, nb->len));
1677       if (pppControl[pd].netif.input) {
1678         pppControl[pd].netif.input(nb, &pppControl[pd].netif);
1679         return;
1680       }
1681       break;
1682 
1683     default: {
1684       struct protent *protp;
1685       int i;
1686 
1687       /*
1688        * Upcall the proper protocol input routine.
1689        */
1690       for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) {
1691         if (protp->protocol == protocol && protp->enabled_flag) {
1692           PPPDEBUG(LOG_INFO, ("pppInput[%d]: %s len=%d\n", pd, protp->name, nb->len));
1693           nb = pppSingleBuf(nb);
1694           (*protp->input)(pd, nb->payload, nb->len);
1695           PPPDEBUG(LOG_DETAIL, ("pppInput[%d]: packet processed\n", pd));
1696           goto out;
1697         }
1698       }
1699 
1700       /* No handler for this protocol so reject the packet. */
1701       PPPDEBUG(LOG_INFO, ("pppInput[%d]: rejecting unsupported proto 0x%"X16_F" len=%d\n", pd, protocol, nb->len));
1702       if (pbuf_header(nb, sizeof(protocol))) {
1703         LWIP_ASSERT("pbuf_header failed\n", 0);
1704         goto drop;
1705       }
1706 #if BYTE_ORDER == LITTLE_ENDIAN
1707       protocol = htons(protocol);
1708 #endif /* BYTE_ORDER == LITTLE_ENDIAN */
1709       SMEMCPY(nb->payload, &protocol, sizeof(protocol));
1710       lcp_sprotrej(pd, nb->payload, nb->len);
1711     }
1712     break;
1713   }
1714 
1715 drop:
1716   LINK_STATS_INC(link.drop);
1717   snmp_inc_ifindiscards(&pppControl[pd].netif);
1718 
1719 out:
1720   pbuf_free(nb);
1721   return;
1722 }
1723 
1724 #if PPPOS_SUPPORT
1725 /*
1726  * Drop the input packet.
1727  */
1728 static void
1729 pppFreeCurrentInputPacket(PPPControlRx *pcrx)
1730 {
1731   if (pcrx->inHead != NULL) {
1732     if (pcrx->inTail && (pcrx->inTail != pcrx->inHead)) {
1733       pbuf_free(pcrx->inTail);
1734     }
1735     pbuf_free(pcrx->inHead);
1736     pcrx->inHead = NULL;
1737   }
1738   pcrx->inTail = NULL;
1739 }
1740 
1741 /*
1742  * Drop the input packet and increase error counters.
1743  */
1744 static void
1745 pppDrop(PPPControlRx *pcrx)
1746 {
1747   if (pcrx->inHead != NULL) {
1748 #if 0
1749     PPPDEBUG(LOG_INFO, ("pppDrop: %d:%.*H\n", pcrx->inHead->len, min(60, pcrx->inHead->len * 2), pcrx->inHead->payload));
1750 #endif
1751     PPPDEBUG(LOG_INFO, ("pppDrop: pbuf len=%d, addr %p\n", pcrx->inHead->len, (void*)pcrx->inHead));
1752   }
1753   pppFreeCurrentInputPacket(pcrx);
1754 #if VJ_SUPPORT
1755   vj_uncompress_err(&pppControl[pcrx->pd].vjComp);
1756 #endif /* VJ_SUPPORT */
1757 
1758   LINK_STATS_INC(link.drop);
1759   snmp_inc_ifindiscards(&pppControl[pcrx->pd].netif);
1760 }
1761 
1762 #if !PPP_INPROC_OWNTHREAD
1763 /** Pass received raw characters to PPPoS to be decoded. This function is
1764  * thread-safe and can be called from a dedicated RX-thread or from a main-loop.
1765  *
1766  * @param pd PPP descriptor index, returned by pppOpen()
1767  * @param data received data
1768  * @param len length of received data
1769  */
1770 void
1771 pppos_input(int pd, u_char* data, int len)
1772 {
1773   pppInProc(&pppControl[pd].rx, data, len);
1774 }
1775 #endif
1776 
1777 /**
1778  * Process a received octet string.
1779  */
1780 static void
1781 pppInProc(PPPControlRx *pcrx, u_char *s, int l)
1782 {
1783   struct pbuf *nextNBuf;
1784   u_char curChar;
1785   u_char escaped;
1786   SYS_ARCH_DECL_PROTECT(lev);
1787 
1788   PPPDEBUG(LOG_DEBUG, ("pppInProc[%d]: got %d bytes\n", pcrx->pd, l));
1789   while (l-- > 0) {
1790     curChar = *s++;
1791 
1792     SYS_ARCH_PROTECT(lev);
1793     escaped = ESCAPE_P(pcrx->inACCM, curChar);
1794     SYS_ARCH_UNPROTECT(lev);
1795     /* Handle special characters. */
1796     if (escaped) {
1797       /* Check for escape sequences. */
1798       /* XXX Note that this does not handle an escaped 0x5d character which
1799        * would appear as an escape character.  Since this is an ASCII ']'
1800        * and there is no reason that I know of to escape it, I won't complicate
1801        * the code to handle this case. GLL */
1802       if (curChar == PPP_ESCAPE) {
1803         pcrx->inEscaped = 1;
1804       /* Check for the flag character. */
1805       } else if (curChar == PPP_FLAG) {
1806         /* If this is just an extra flag character, ignore it. */
1807         if (pcrx->inState <= PDADDRESS) {
1808           /* ignore it */;
1809         /* If we haven't received the packet header, drop what has come in. */
1810         } else if (pcrx->inState < PDDATA) {
1811           PPPDEBUG(LOG_WARNING,
1812                    ("pppInProc[%d]: Dropping incomplete packet %d\n",
1813                     pcrx->pd, pcrx->inState));
1814           LINK_STATS_INC(link.lenerr);
1815           pppDrop(pcrx);
1816         /* If the fcs is invalid, drop the packet. */
1817         } else if (pcrx->inFCS != PPP_GOODFCS) {
1818           PPPDEBUG(LOG_INFO,
1819                    ("pppInProc[%d]: Dropping bad fcs 0x%"X16_F" proto=0x%"X16_F"\n",
1820                     pcrx->pd, pcrx->inFCS, pcrx->inProtocol));
1821           /* Note: If you get lots of these, check for UART frame errors or try different baud rate */
1822           LINK_STATS_INC(link.chkerr);
1823           pppDrop(pcrx);
1824         /* Otherwise it's a good packet so pass it on. */
1825         } else {
1826           struct pbuf *inp;
1827           /* Trim off the checksum. */
1828           if(pcrx->inTail->len >= 2) {
1829             pcrx->inTail->len -= 2;
1830 
1831             pcrx->inTail->tot_len = pcrx->inTail->len;
1832             if (pcrx->inTail != pcrx->inHead) {
1833               pbuf_cat(pcrx->inHead, pcrx->inTail);
1834             }
1835           } else {
1836             pcrx->inTail->tot_len = pcrx->inTail->len;
1837             if (pcrx->inTail != pcrx->inHead) {
1838               pbuf_cat(pcrx->inHead, pcrx->inTail);
1839             }
1840 
1841             pbuf_realloc(pcrx->inHead, pcrx->inHead->tot_len - 2);
1842           }
1843 
1844           /* Dispatch the packet thereby consuming it. */
1845           inp = pcrx->inHead;
1846           /* Packet consumed, release our references. */
1847           pcrx->inHead = NULL;
1848           pcrx->inTail = NULL;
1849 #if PPP_INPROC_MULTITHREADED
1850           if(tcpip_callback_with_block(pppInput, inp, 0) != ERR_OK) {
1851             PPPDEBUG(LOG_ERR, ("pppInProc[%d]: tcpip_callback() failed, dropping packet\n", pcrx->pd));
1852             pbuf_free(inp);
1853             LINK_STATS_INC(link.drop);
1854             snmp_inc_ifindiscards(&pppControl[pcrx->pd].netif);
1855           }
1856 #else /* PPP_INPROC_MULTITHREADED */
1857           pppInput(inp);
1858 #endif /* PPP_INPROC_MULTITHREADED */
1859         }
1860 
1861         /* Prepare for a new packet. */
1862         pcrx->inFCS = PPP_INITFCS;
1863         pcrx->inState = PDADDRESS;
1864         pcrx->inEscaped = 0;
1865       /* Other characters are usually control characters that may have
1866        * been inserted by the physical layer so here we just drop them. */
1867       } else {
1868         PPPDEBUG(LOG_WARNING,
1869                  ("pppInProc[%d]: Dropping ACCM char <%d>\n", pcrx->pd, curChar));
1870       }
1871     /* Process other characters. */
1872     } else {
1873       /* Unencode escaped characters. */
1874       if (pcrx->inEscaped) {
1875         pcrx->inEscaped = 0;
1876         curChar ^= PPP_TRANS;
1877       }
1878 
1879       /* Process character relative to current state. */
1880       switch(pcrx->inState) {
1881         case PDIDLE:                    /* Idle state - waiting. */
1882           /* Drop the character if it's not 0xff
1883            * we would have processed a flag character above. */
1884           if (curChar != PPP_ALLSTATIONS) {
1885             break;
1886           }
1887 
1888         /* Fall through */
1889         case PDSTART:                   /* Process start flag. */
1890           /* Prepare for a new packet. */
1891           pcrx->inFCS = PPP_INITFCS;
1892 
1893         /* Fall through */
1894         case PDADDRESS:                 /* Process address field. */
1895           if (curChar == PPP_ALLSTATIONS) {
1896             pcrx->inState = PDCONTROL;
1897             break;
1898           }
1899           /* Else assume compressed address and control fields so
1900            * fall through to get the protocol... */
1901         case PDCONTROL:                 /* Process control field. */
1902           /* If we don't get a valid control code, restart. */
1903           if (curChar == PPP_UI) {
1904             pcrx->inState = PDPROTOCOL1;
1905             break;
1906           }
1907 #if 0
1908           else {
1909             PPPDEBUG(LOG_WARNING,
1910                      ("pppInProc[%d]: Invalid control <%d>\n", pcrx->pd, curChar));
1911             pcrx->inState = PDSTART;
1912           }
1913 #endif
1914         case PDPROTOCOL1:               /* Process protocol field 1. */
1915           /* If the lower bit is set, this is the end of the protocol
1916            * field. */
1917           if (curChar & 1) {
1918             pcrx->inProtocol = curChar;
1919             pcrx->inState = PDDATA;
1920           } else {
1921             pcrx->inProtocol = (u_int)curChar << 8;
1922             pcrx->inState = PDPROTOCOL2;
1923           }
1924           break;
1925         case PDPROTOCOL2:               /* Process protocol field 2. */
1926           pcrx->inProtocol |= curChar;
1927           pcrx->inState = PDDATA;
1928           break;
1929         case PDDATA:                    /* Process data byte. */
1930           /* Make space to receive processed data. */
1931           if (pcrx->inTail == NULL || pcrx->inTail->len == PBUF_POOL_BUFSIZE) {
1932             if (pcrx->inTail != NULL) {
1933               pcrx->inTail->tot_len = pcrx->inTail->len;
1934               if (pcrx->inTail != pcrx->inHead) {
1935                 pbuf_cat(pcrx->inHead, pcrx->inTail);
1936                 /* give up the inTail reference now */
1937                 pcrx->inTail = NULL;
1938               }
1939             }
1940             /* If we haven't started a packet, we need a packet header. */
1941             nextNBuf = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
1942             if (nextNBuf == NULL) {
1943               /* No free buffers.  Drop the input packet and let the
1944                * higher layers deal with it.  Continue processing
1945                * the received pbuf chain in case a new packet starts. */
1946               PPPDEBUG(LOG_ERR, ("pppInProc[%d]: NO FREE MBUFS!\n", pcrx->pd));
1947               LINK_STATS_INC(link.memerr);
1948               pppDrop(pcrx);
1949               pcrx->inState = PDSTART;  /* Wait for flag sequence. */
1950               break;
1951             }
1952             if (pcrx->inHead == NULL) {
1953               struct pppInputHeader *pih = nextNBuf->payload;
1954 
1955               pih->unit = pcrx->pd;
1956               pih->proto = pcrx->inProtocol;
1957 
1958               nextNBuf->len += sizeof(*pih);
1959 
1960               pcrx->inHead = nextNBuf;
1961             }
1962             pcrx->inTail = nextNBuf;
1963           }
1964           /* Load character into buffer. */
1965           ((u_char*)pcrx->inTail->payload)[pcrx->inTail->len++] = curChar;
1966           break;
1967       }
1968 
1969       /* update the frame check sequence number. */
1970       pcrx->inFCS = PPP_FCS(pcrx->inFCS, curChar);
1971     }
1972   } /* while (l-- > 0), all bytes processed */
1973 
1974   avRandomize();
1975 }
1976 #endif /* PPPOS_SUPPORT */
1977 
1978 #if PPPOE_SUPPORT
1979 void
1980 pppInProcOverEthernet(int pd, struct pbuf *pb)
1981 {
1982   struct pppInputHeader *pih;
1983   u16_t inProtocol;
1984 
1985   if(pb->len < sizeof(inProtocol)) {
1986     PPPDEBUG(LOG_ERR, ("pppInProcOverEthernet: too small for protocol field\n"));
1987     goto drop;
1988   }
1989 
1990   inProtocol = (((u8_t *)pb->payload)[0] << 8) | ((u8_t*)pb->payload)[1];
1991 
1992   /* make room for pppInputHeader - should not fail */
1993   if (pbuf_header(pb, sizeof(*pih) - sizeof(inProtocol)) != 0) {
1994     PPPDEBUG(LOG_ERR, ("pppInProcOverEthernet: could not allocate room for header\n"));
1995     goto drop;
1996   }
1997 
1998   pih = pb->payload;
1999 
2000   pih->unit = pd;
2001   pih->proto = inProtocol;
2002 
2003   /* Dispatch the packet thereby consuming it. */
2004   pppInput(pb);
2005   return;
2006 
2007 drop:
2008   LINK_STATS_INC(link.drop);
2009   snmp_inc_ifindiscards(&pppControl[pd].netif);
2010   pbuf_free(pb);
2011   return;
2012 }
2013 #endif /* PPPOE_SUPPORT */
2014 
2015 #if LWIP_NETIF_STATUS_CALLBACK
2016 /** Set the status callback of a PPP's netif
2017  *
2018  * @param pd The PPP descriptor returned by pppOpen()
2019  * @param status_callback pointer to the status callback function
2020  *
2021  * @see netif_set_status_callback
2022  */
2023 void
2024 ppp_set_netif_statuscallback(int pd, netif_status_callback_fn status_callback)
2025 {
2026   netif_set_status_callback(&pppControl[pd].netif, status_callback);
2027 }
2028 #endif /* LWIP_NETIF_STATUS_CALLBACK */
2029 
2030 #if LWIP_NETIF_LINK_CALLBACK
2031 /** Set the link callback of a PPP's netif
2032  *
2033  * @param pd The PPP descriptor returned by pppOpen()
2034  * @param link_callback pointer to the link callback function
2035  *
2036  * @see netif_set_link_callback
2037  */
2038 void
2039 ppp_set_netif_linkcallback(int pd, netif_status_callback_fn link_callback)
2040 {
2041   netif_set_link_callback(&pppControl[pd].netif, link_callback);
2042 }
2043 #endif /* LWIP_NETIF_LINK_CALLBACK */
2044 
2045 #endif /* PPP_SUPPORT */
2046