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