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