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