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