]> rtime.felk.cvut.cz Git - pes-rpp/rpp-lwip.git/blob - src/netif/ppp/ppp.c
Merged from DEVEL into main tree.
[pes-rpp/rpp-lwip.git] / 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         pppControl[i].netif = NULL;
300
301                 subnetMask = htonl(0xffffff00);
302     
303         /*
304          * Initialize to the standard option set.
305          */
306         for (j = 0; (protp = ppp_protocols[j]) != NULL; ++j)
307             (*protp->init)(i);
308     }
309
310 #if LINK_STATS
311     /* Clear the statistics. */
312     memset(&lwip_stats.link, 0, sizeof(lwip_stats.link));
313 #endif
314 }
315
316 void pppSetAuth(enum pppAuthType authType, const char *user, const char *passwd)
317 {
318     switch(authType) {
319         case PPPAUTHTYPE_NONE:
320         default:
321 #ifdef LWIP_PPP_STRICT_PAP_REJECT
322             ppp_settings.refuse_pap = 1;
323 #else
324             /* some providers request pap and accept an empty login/pw */
325             ppp_settings.refuse_pap = 0;
326 #endif
327             ppp_settings.refuse_chap = 1;
328             break;
329         case PPPAUTHTYPE_ANY:
330 /* Warning: Using PPPAUTHTYPE_ANY might have security consequences.
331  * RFC 1994 says:
332  *
333  * In practice, within or associated with each PPP server, there is a
334  * database which associates "user" names with authentication
335  * information ("secrets").  It is not anticipated that a particular
336  * named user would be authenticated by multiple methods.  This would
337  * make the user vulnerable to attacks which negotiate the least secure
338  * method from among a set (such as PAP rather than CHAP).  If the same
339  * secret was used, PAP would reveal the secret to be used later with
340  * CHAP.
341  *
342  * Instead, for each user name there should be an indication of exactly
343  * one method used to authenticate that user name.  If a user needs to
344  * make use of different authentication methods under different
345  * circumstances, then distinct user names SHOULD be employed, each of
346  * which identifies exactly one authentication method.
347  *
348  */
349             ppp_settings.refuse_pap = 0;
350             ppp_settings.refuse_chap = 0;
351             break;
352         case PPPAUTHTYPE_PAP:
353             ppp_settings.refuse_pap = 0;
354             ppp_settings.refuse_chap = 1;
355             break;
356         case PPPAUTHTYPE_CHAP:
357             ppp_settings.refuse_pap = 1;
358             ppp_settings.refuse_chap = 0;
359             break;
360     }
361
362     if(user) {
363         strncpy(ppp_settings.user, user, sizeof(ppp_settings.user)-1);
364         ppp_settings.user[sizeof(ppp_settings.user)-1] = '\0';
365     } else
366         ppp_settings.user[0] = '\0';
367
368     if(passwd) {
369         strncpy(ppp_settings.passwd, passwd, sizeof(ppp_settings.passwd)-1);
370         ppp_settings.passwd[sizeof(ppp_settings.passwd)-1] = '\0';
371     } else
372         ppp_settings.passwd[0] = '\0';
373 }
374
375 /* Open a new PPP connection using the given I/O device.
376  * This initializes the PPP control block but does not
377  * attempt to negotiate the LCP session.  If this port
378  * connects to a modem, the modem connection must be
379  * established before calling this.
380  * Return a new PPP connection descriptor on success or
381  * an error code (negative) on failure. */
382 int pppOpen(sio_fd_t fd, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx)
383 {
384     PPPControl *pc;
385     int pd;
386
387     /* Find a free PPP session descriptor. Critical region? */
388     for (pd = 0; pd < NUM_PPP && pppControl[pd].openFlag != 0; pd++);
389     if (pd >= NUM_PPP)
390         pd = PPPERR_OPEN;
391     else
392         pppControl[pd].openFlag = !0;
393
394     /* Launch a deamon thread. */
395     if (pd >= 0) {
396
397         pppControl[pd].openFlag = 1;
398
399         lcp_init(pd);
400         pc = &pppControl[pd];
401         pc->fd = fd;
402         pc->kill_link = 0;
403         pc->sig_hup = 0;
404         pc->if_up = 0;
405         pc->errCode = 0;
406         pc->inState = PDIDLE;
407         pc->inHead = NULL;
408         pc->inTail = NULL;
409         pc->inEscaped = 0;
410         pc->lastXMit = 0;
411
412 #if VJ_SUPPORT > 0
413         pc->vjEnabled = 0;
414         vj_compress_init(&pc->vjComp);
415 #endif
416
417         /* 
418          * Default the in and out accm so that escape and flag characters
419          * are always escaped. 
420          */
421         memset(pc->inACCM, 0, sizeof(ext_accm));
422         pc->inACCM[15] = 0x60;
423         memset(pc->outACCM, 0, sizeof(ext_accm));
424         pc->outACCM[15] = 0x60;
425
426         pc->linkStatusCB = linkStatusCB;
427         pc->linkStatusCtx = linkStatusCtx;
428
429         sys_thread_new(pppMain, (void*)pd, PPP_THREAD_PRIO);
430         if(!linkStatusCB) {
431                 while(pd >= 0 && !pc->if_up) {
432                         sys_msleep(500);
433                         if (lcp_phase[pd] == PHASE_DEAD) {
434                                 pppClose(pd);
435                                 if (pc->errCode)
436                                         pd = pc->errCode;
437                                 else
438                                         pd = PPPERR_CONNECT;
439                         }
440                 }
441         }
442     }
443     return pd;
444 }
445
446 /* Close a PPP connection and release the descriptor. 
447  * Any outstanding packets in the queues are dropped.
448  * Return 0 on success, an error code on failure. */
449 int pppClose(int pd)
450 {
451     PPPControl *pc = &pppControl[pd];
452     int st = 0;
453
454     /* Disconnect */
455     pc->kill_link = !0;
456     pppMainWakeup(pd);
457     
458     if(!pc->linkStatusCB) {
459             while(st >= 0 && lcp_phase[pd] != PHASE_DEAD) {
460                     sys_msleep(500);
461                     break;
462             }
463     }
464     return st;
465 }
466
467 /* This function is called when carrier is lost on the PPP channel. */
468 void pppSigHUP(int pd)
469 {
470     PPPControl *pc = &pppControl[pd];
471
472     pc->sig_hup = 1;
473     pppMainWakeup(pd);
474 }
475
476 static void nPut(PPPControl *pc, struct pbuf *nb)
477 {
478         struct pbuf *b;
479         int c;
480
481         for(b = nb; b != NULL; b = b->next) {
482             if((c = sio_write(pc->fd, b->payload, b->len)) != b->len) {
483                 PPPDEBUG((LOG_WARNING,
484                             "PPP nPut: incomplete sio_write(%d,, %u) = %d\n", pc->fd, b->len, c));
485 #if LINK_STATS
486                 lwip_stats.link.err++;
487 #endif /* LINK_STATS */
488                 pc->lastXMit = 0; /* prepend PPP_FLAG to next packet */
489                 break;
490             }
491         }
492         pbuf_free(nb);
493
494 #if LINK_STATS
495         lwip_stats.link.xmit++;
496 #endif /* LINK_STATS */
497 }
498
499 /* 
500  * pppAppend - append given character to end of given pbuf.  If outACCM
501  * is not NULL and the character needs to be escaped, do so.
502  * If pbuf is full, append another.
503  * Return the current pbuf.
504  */
505 static struct pbuf *pppAppend(u_char c, struct pbuf *nb, ext_accm *outACCM)
506 {
507     struct pbuf *tb = nb;
508     
509     /* Make sure there is room for the character and an escape code.
510      * Sure we don't quite fill the buffer if the character doesn't
511      * get escaped but is one character worth complicating this? */
512     /* Note: We assume no packet header. */
513     if (nb && (PBUF_POOL_BUFSIZE - nb->len) < 2) {
514         tb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
515         if (tb) {
516             nb->next = tb;
517         }
518 #if LINK_STATS
519         else {
520             lwip_stats.link.memerr++;
521         }
522 #endif /* LINK_STATS */
523         nb = tb;
524     }
525     if (nb) {
526         if (outACCM && ESCAPE_P(*outACCM, c)) {
527             *((u_char*)nb->payload + nb->len++) = PPP_ESCAPE;
528             *((u_char*)nb->payload + nb->len++) = c ^ PPP_TRANS;
529         }
530         else
531             *((u_char*)nb->payload + nb->len++) = c;
532     }
533         
534     return tb;
535 }
536
537 /* Send a packet on the given connection. */
538 static err_t pppifOutput(struct netif *netif, struct pbuf *pb, struct ip_addr *ipaddr)
539 {
540         int pd = (int)netif->state;
541         u_short protocol = PPP_IP;
542     PPPControl *pc = &pppControl[pd];
543     u_int fcsOut = PPP_INITFCS;
544     struct pbuf *headMB = NULL, *tailMB = NULL, *p;
545     u_char c;
546
547         (void)ipaddr;
548
549     /* Validate parameters. */
550     /* We let any protocol value go through - it can't hurt us
551      * and the peer will just drop it if it's not accepting it. */
552         if (pd < 0 || pd >= NUM_PPP || !pc->openFlag || !pb) {
553         PPPDEBUG((LOG_WARNING, "pppifOutput[%d]: bad parms prot=%d pb=%p\n",
554                     pd, protocol, pb));
555 #if LINK_STATS
556                 lwip_stats.link.opterr++;
557                 lwip_stats.link.drop++;
558 #endif
559                 return ERR_ARG;
560         }
561
562     /* Check that the link is up. */
563         if (lcp_phase[pd] == PHASE_DEAD) {
564         PPPDEBUG((LOG_ERR, "pppifOutput[%d]: link not up\n", pd));
565 #if LINK_STATS
566                 lwip_stats.link.rterr++;
567                 lwip_stats.link.drop++;
568 #endif
569                 return ERR_RTE;
570         }
571
572     /* Grab an output buffer. */
573         headMB = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
574     if (headMB == NULL) {
575         PPPDEBUG((LOG_WARNING, "pppifOutput[%d]: first alloc fail\n", pd));
576 #if LINK_STATS
577                 lwip_stats.link.memerr++;
578                 lwip_stats.link.drop++;
579 #endif /* LINK_STATS */
580         return ERR_MEM;
581     }
582         
583 #if VJ_SUPPORT > 0
584     /* 
585      * Attempt Van Jacobson header compression if VJ is configured and
586      * this is an IP packet. 
587      */
588     if (protocol == PPP_IP && pc->vjEnabled) {
589         switch (vj_compress_tcp(&pc->vjComp, pb)) {
590         case TYPE_IP:
591             /* No change...
592             protocol = PPP_IP_PROTOCOL;
593              */
594             break;
595         case TYPE_COMPRESSED_TCP:
596             protocol = PPP_VJC_COMP;
597             break;
598         case TYPE_UNCOMPRESSED_TCP:
599             protocol = PPP_VJC_UNCOMP;
600             break;
601         default:
602             PPPDEBUG((LOG_WARNING, "pppifOutput[%d]: bad IP packet\n", pd));
603 #if LINK_STATS
604                         lwip_stats.link.proterr++;
605                         lwip_stats.link.drop++;
606 #endif
607                 pbuf_free(headMB);
608             return ERR_VAL;
609         }
610     }
611 #endif
612         
613     tailMB = headMB;
614         
615     /* Build the PPP header. */
616     if ((sys_jiffies() - pc->lastXMit) >= PPP_MAXIDLEFLAG)
617         tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
618     pc->lastXMit = sys_jiffies();
619     if (!pc->accomp) {
620         fcsOut = PPP_FCS(fcsOut, PPP_ALLSTATIONS);
621         tailMB = pppAppend(PPP_ALLSTATIONS, tailMB, &pc->outACCM);
622         fcsOut = PPP_FCS(fcsOut, PPP_UI);
623         tailMB = pppAppend(PPP_UI, tailMB, &pc->outACCM);
624     }
625     if (!pc->pcomp || protocol > 0xFF) {
626         c = (protocol >> 8) & 0xFF;
627         fcsOut = PPP_FCS(fcsOut, c);
628         tailMB = pppAppend(c, tailMB, &pc->outACCM);
629     }
630     c = protocol & 0xFF;
631     fcsOut = PPP_FCS(fcsOut, c);
632     tailMB = pppAppend(c, tailMB, &pc->outACCM);
633     
634     /* Load packet. */
635         for(p = pb; p; p = p->next) {
636         int n;
637         u_char *sPtr;
638
639         sPtr = (u_char*)p->payload;
640         n = p->len;
641         while (n-- > 0) {
642             c = *sPtr++;
643             
644             /* Update FCS before checking for special characters. */
645             fcsOut = PPP_FCS(fcsOut, c);
646             
647             /* Copy to output buffer escaping special characters. */
648             tailMB = pppAppend(c, tailMB, &pc->outACCM);
649         }
650     }
651
652     /* Add FCS and trailing flag. */
653     c = ~fcsOut & 0xFF;
654     tailMB = pppAppend(c, tailMB, &pc->outACCM);
655     c = (~fcsOut >> 8) & 0xFF;
656     tailMB = pppAppend(c, tailMB, &pc->outACCM);
657     tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
658         
659     /* If we failed to complete the packet, throw it away. */
660     if (!tailMB) {
661         PPPDEBUG((LOG_WARNING,
662                     "pppifOutput[%d]: Alloc err - dropping proto=%d\n", 
663                     pd, protocol));
664         pbuf_free(headMB);
665 #if LINK_STATS
666                 lwip_stats.link.memerr++;
667                 lwip_stats.link.drop++;
668 #endif
669         return ERR_MEM;
670     }
671
672         /* Send it. */
673     PPPDEBUG((LOG_INFO, "pppifOutput[%d]: proto=0x%04X\n", pd, protocol));
674
675     nPut(pc, headMB);
676
677     return ERR_OK;
678 }
679
680 /* Get and set parameters for the given connection.
681  * Return 0 on success, an error code on failure. */
682 int  pppIOCtl(int pd, int cmd, void *arg)
683 {
684     PPPControl *pc = &pppControl[pd];
685     int st = 0;
686
687     if (pd < 0 || pd >= NUM_PPP)
688         st = PPPERR_PARAM;
689     else {
690         switch(cmd) {
691         case PPPCTLG_UPSTATUS:      /* Get the PPP up status. */
692             if (arg) 
693                 *(int *)arg = (int)(pc->if_up);
694             else
695                 st = PPPERR_PARAM;
696             break;
697         case PPPCTLS_ERRCODE:       /* Set the PPP error code. */
698             if (arg) 
699                 pc->errCode = *(int *)arg;
700             else
701                 st = PPPERR_PARAM;
702             break;
703         case PPPCTLG_ERRCODE:       /* Get the PPP error code. */
704             if (arg) 
705                 *(int *)arg = (int)(pc->errCode);
706             else
707                 st = PPPERR_PARAM;
708             break;
709         case PPPCTLG_FD:
710             if (arg) 
711                 *(sio_fd_t *)arg = pc->fd;
712             else
713                 st = PPPERR_PARAM;
714             break;
715         default:
716             st = PPPERR_PARAM;
717             break;
718         }
719     }
720     
721     return st;
722 }
723
724 /*
725  * Return the Maximum Transmission Unit for the given PPP connection.
726  */
727 u_int pppMTU(int pd)
728 {
729     PPPControl *pc = &pppControl[pd];
730     u_int st;
731     
732     /* Validate parameters. */
733     if (pd < 0 || pd >= NUM_PPP || !pc->openFlag)
734         st = 0;
735     else
736         st = pc->mtu;
737         
738     return st;
739 }
740
741 /*
742  * Write n characters to a ppp link.
743  *  RETURN: >= 0 Number of characters written
744  *           -1 Failed to write to device
745  */
746 int pppWrite(int pd, const u_char *s, int n)
747 {
748     PPPControl *pc = &pppControl[pd];
749     u_char c;
750     u_int fcsOut = PPP_INITFCS;
751     struct pbuf *headMB = NULL, *tailMB;
752         headMB = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
753     if (headMB == NULL) {
754 #if LINK_STATS
755                 lwip_stats.link.memerr++;
756                 lwip_stats.link.proterr++;
757 #endif /* LINK_STATS */
758                 return PPPERR_ALLOC;
759     }
760
761     tailMB = headMB;
762         
763     /* If the link has been idle, we'll send a fresh flag character to
764      * flush any noise. */
765     if ((sys_jiffies() - pc->lastXMit) >= PPP_MAXIDLEFLAG)
766         tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
767     pc->lastXMit = sys_jiffies();
768      
769     /* Load output buffer. */
770     while (n-- > 0) {
771         c = *s++;
772         
773         /* Update FCS before checking for special characters. */
774         fcsOut = PPP_FCS(fcsOut, c);
775         
776         /* Copy to output buffer escaping special characters. */
777         tailMB = pppAppend(c, tailMB, &pc->outACCM);
778     }
779     
780     /* Add FCS and trailing flag. */
781     c = ~fcsOut & 0xFF;
782     tailMB = pppAppend(c, tailMB, &pc->outACCM);
783     c = (~fcsOut >> 8) & 0xFF;
784     tailMB = pppAppend(c, tailMB, &pc->outACCM);
785     tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
786         
787     /* If we failed to complete the packet, throw it away.
788      * Otherwise send it. */
789     if (!tailMB) {
790                 PPPDEBUG((LOG_WARNING,
791                 "pppWrite[%d]: Alloc err - dropping pbuf len=%d\n", pd, headMB->len));
792 /*                "pppWrite[%d]: Alloc err - dropping %d:%.*H", pd, headMB->len, LWIP_MIN(headMB->len * 2, 40), headMB->payload)); */
793                 pbuf_free(headMB);
794 #if LINK_STATS
795                 lwip_stats.link.memerr++;
796                 lwip_stats.link.proterr++;
797 #endif /* LINK_STATS */
798                 return PPPERR_ALLOC;
799         }
800
801     PPPDEBUG((LOG_INFO, "pppWrite[%d]: len=%d\n", pd, headMB->len));
802 /*     "pppWrite[%d]: %d:%.*H", pd, headMB->len, LWIP_MIN(headMB->len * 2, 40), headMB->payload)); */
803     nPut(pc, headMB);
804
805     return PPPERR_NONE;
806 }
807
808 /*
809  * ppp_send_config - configure the transmit characteristics of
810  * the ppp interface.
811  */
812 void ppp_send_config(
813     int unit, 
814     int mtu,
815     u32_t asyncmap,
816     int pcomp, 
817     int accomp
818 )
819 {
820     PPPControl *pc = &pppControl[unit];
821     int i;
822     
823     pc->mtu = mtu;
824     pc->pcomp = pcomp;
825     pc->accomp = accomp;
826     
827     /* Load the ACCM bits for the 32 control codes. */
828     for (i = 0; i < 32/8; i++)
829         pc->outACCM[i] = (u_char)((asyncmap >> (8 * i)) & 0xFF);
830     PPPDEBUG((LOG_INFO, "ppp_send_config[%d]: outACCM=%X %X %X %X\n",
831                 unit,
832                 pc->outACCM[0], pc->outACCM[1], pc->outACCM[2], pc->outACCM[3]));
833 }
834
835
836 /*
837  * ppp_set_xaccm - set the extended transmit ACCM for the interface.
838  */
839 void ppp_set_xaccm(int unit, ext_accm *accm)
840 {
841     memcpy(pppControl[unit].outACCM, accm, sizeof(ext_accm));
842     PPPDEBUG((LOG_INFO, "ppp_set_xaccm[%d]: outACCM=%X %X %X %X\n",
843                 unit,
844                 pppControl[unit].outACCM[0],
845                 pppControl[unit].outACCM[1],
846                 pppControl[unit].outACCM[2],
847                 pppControl[unit].outACCM[3]));
848 }
849
850
851 /*
852  * ppp_recv_config - configure the receive-side characteristics of
853  * the ppp interface.
854  */
855 void ppp_recv_config(
856     int unit, 
857     int mru,
858     u32_t asyncmap,
859     int pcomp, 
860     int accomp
861 )
862 {
863     PPPControl *pc = &pppControl[unit];
864     int i;
865     
866         (void)accomp;
867         (void)pcomp;
868         (void)mru;
869
870     /* Load the ACCM bits for the 32 control codes. */
871     for (i = 0; i < 32 / 8; i++)
872         pc->inACCM[i] = (u_char)(asyncmap >> (i * 8));
873     PPPDEBUG((LOG_INFO, "ppp_recv_config[%d]: inACCM=%X %X %X %X\n",
874                 unit,
875                 pc->inACCM[0], pc->inACCM[1], pc->inACCM[2], pc->inACCM[3]));
876 }
877
878 #if 0
879 /*
880  * ccp_test - ask kernel whether a given compression method
881  * is acceptable for use.  Returns 1 if the method and parameters
882  * are OK, 0 if the method is known but the parameters are not OK
883  * (e.g. code size should be reduced), or -1 if the method is unknown.
884  */
885 int ccp_test(
886     int unit, 
887     int opt_len, 
888     int for_transmit,
889     u_char *opt_ptr
890 )
891 {
892     return 0;   /* XXX Currently no compression. */
893 }
894
895 /*
896  * ccp_flags_set - inform kernel about the current state of CCP.
897  */
898 void ccp_flags_set(int unit, int isopen, int isup)
899 {
900     /* XXX */
901 }
902
903 /*
904  * ccp_fatal_error - returns 1 if decompression was disabled as a
905  * result of an error detected after decompression of a packet,
906  * 0 otherwise.  This is necessary because of patent nonsense.
907  */
908 int ccp_fatal_error(int unit)
909 {
910     /* XXX */
911     return 0;
912 }
913 #endif
914
915 /*
916  * get_idle_time - return how long the link has been idle.
917  */
918 int get_idle_time(int u, struct ppp_idle *ip)
919 {   
920     /* XXX */
921         (void)u;
922         (void)ip;
923
924     return 0;
925 }
926
927
928 /*
929  * Return user specified netmask, modified by any mask we might determine
930  * for address `addr' (in network byte order).
931  * Here we scan through the system's list of interfaces, looking for
932  * any non-point-to-point interfaces which might appear to be on the same
933  * network as `addr'.  If we find any, we OR in their netmask to the
934  * user-specified netmask.
935  */
936 u32_t GetMask(u32_t addr)
937 {
938     u32_t mask, nmask;
939     
940     htonl(addr);
941     if (IN_CLASSA(addr))    /* determine network mask for address class */
942         nmask = IN_CLASSA_NET;
943     else if (IN_CLASSB(addr))
944         nmask = IN_CLASSB_NET;
945     else
946         nmask = IN_CLASSC_NET;
947     /* class D nets are disallowed by bad_ip_adrs */
948     mask = subnetMask | htonl(nmask);
949     
950     /* XXX
951      * Scan through the system's network interfaces.
952      * Get each netmask and OR them into our mask.
953      */
954     
955     return mask;
956 }
957
958 /*
959  * sifvjcomp - config tcp header compression
960  */
961 int sifvjcomp(
962     int pd, 
963     int vjcomp, 
964     int cidcomp, 
965     int maxcid
966 )
967 {
968 #if VJ_SUPPORT > 0
969     PPPControl *pc = &pppControl[pd];
970     
971     pc->vjEnabled = vjcomp;
972     pc->vjComp.compressSlot = cidcomp;
973     pc->vjComp.maxSlotIndex = maxcid;
974     PPPDEBUG((LOG_INFO, "sifvjcomp: VJ compress enable=%d slot=%d max slot=%d\n",
975                 vjcomp, cidcomp, maxcid));
976 #endif
977
978     return 0;
979 }
980
981 /*
982  * pppifNetifInit - netif init callback
983  */
984 static err_t pppifNetifInit(struct netif *netif)
985 {
986         netif->name[0] = 'p';
987         netif->name[1] = 'p';
988         netif->output = pppifOutput;
989         netif->mtu = pppMTU((int)netif->state);
990         return ERR_OK;
991 }
992
993
994 /*
995  * sifup - Config the interface up and enable IP packets to pass.
996  */
997 int sifup(int pd)
998 {
999     PPPControl *pc = &pppControl[pd];
1000     int st = 1;
1001     
1002     if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
1003         st = 0;
1004         PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));
1005     } else {
1006                 if(pc->netif)
1007                         netif_remove(pc->netif);
1008                 pc->netif = netif_add(&pc->addrs.our_ipaddr, &pc->addrs.netmask, &pc->addrs.his_ipaddr, (void *)pd, pppifNetifInit, ip_input);
1009                 if(pc->netif) {
1010                 pc->if_up = 1;
1011                 pc->errCode = PPPERR_NONE;
1012
1013                         PPPDEBUG((LOG_DEBUG, "sifup: unit %d: linkStatusCB=%lx errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));
1014                         if(pc->linkStatusCB)
1015                                 pc->linkStatusCB(pc->linkStatusCtx, pc->errCode, &pc->addrs);
1016                 } else {
1017                 st = 0;
1018                 PPPDEBUG((LOG_ERR, "sifup[%d]: netif_add failed\n", pd));
1019                 }
1020     }
1021
1022     return st;
1023 }
1024
1025 /*
1026  * sifnpmode - Set the mode for handling packets for a given NP.
1027  */
1028 int sifnpmode(int u, int proto, enum NPmode mode)
1029 {
1030         (void)u;
1031         (void)proto;
1032         (void)mode;
1033     return 0;
1034 }
1035
1036 /*
1037  * sifdown - Config the interface down and disable IP.
1038  */
1039 int sifdown(int pd)
1040 {
1041     PPPControl *pc = &pppControl[pd];
1042     int st = 1;
1043     
1044     if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
1045         st = 0;
1046         PPPDEBUG((LOG_WARNING, "sifdown[%d]: bad parms\n", pd));
1047     } else {
1048         pc->if_up = 0;
1049                 if(pc->netif)
1050                         netif_remove(pc->netif);
1051                 pc->netif = NULL;
1052                 PPPDEBUG((LOG_DEBUG, "sifdown: unit %d: linkStatusCB=%lx errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));
1053                 if(pc->linkStatusCB)
1054                         pc->linkStatusCB(pc->linkStatusCtx, PPPERR_CONNECT, NULL);
1055         }
1056     return st;
1057 }
1058
1059 /*
1060  * sifaddr - Config the interface IP addresses and netmask.
1061  */
1062 int sifaddr(
1063     int pd,             /* Interface unit ??? */
1064     u32_t o,        /* Our IP address ??? */
1065     u32_t h,        /* His IP address ??? */
1066     u32_t m,        /* IP subnet mask ??? */
1067     u32_t ns1,      /* Primary DNS */
1068     u32_t ns2       /* Secondary DNS */
1069 )
1070 {
1071     PPPControl *pc = &pppControl[pd];
1072     int st = 1;
1073     
1074     if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
1075         st = 0;
1076         PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));
1077     } else {
1078                 memcpy(&pc->addrs.our_ipaddr, &o, sizeof(o));
1079                 memcpy(&pc->addrs.his_ipaddr, &h, sizeof(h));
1080                 memcpy(&pc->addrs.netmask, &m, sizeof(m));
1081                 memcpy(&pc->addrs.dns1, &ns1, sizeof(ns1));
1082                 memcpy(&pc->addrs.dns2, &ns2, sizeof(ns2));
1083     }
1084     return st;
1085 }
1086
1087 /*
1088  * cifaddr - Clear the interface IP addresses, and delete routes
1089  * through the interface if possible.
1090  */
1091 int cifaddr(
1092     int pd,         /* Interface unit ??? */
1093     u32_t o,    /* Our IP address ??? */
1094     u32_t h     /* IP broadcast address ??? */
1095 )
1096 {
1097     PPPControl *pc = &pppControl[pd];
1098     int st = 1;
1099     
1100         (void)o;
1101         (void)h;
1102     if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
1103         st = 0;
1104         PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));
1105     } else {
1106                 IP4_ADDR(&pc->addrs.our_ipaddr, 0,0,0,0);
1107                 IP4_ADDR(&pc->addrs.his_ipaddr, 0,0,0,0);
1108                 IP4_ADDR(&pc->addrs.netmask, 255,255,255,0);
1109                 IP4_ADDR(&pc->addrs.dns1, 0,0,0,0);
1110                 IP4_ADDR(&pc->addrs.dns2, 0,0,0,0);
1111     }
1112     return st;
1113 }
1114
1115 /*
1116  * sifdefaultroute - assign a default route through the address given.
1117  */
1118 int sifdefaultroute(int pd, u32_t l, u32_t g)
1119 {
1120     PPPControl *pc = &pppControl[pd];
1121     int st = 1;
1122     
1123         (void)l;
1124         (void)g;
1125     if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
1126         st = 0;
1127         PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));
1128     } else {
1129                 netif_set_default(pc->netif);
1130     }
1131
1132     /* TODO: check how PPP handled the netMask, previously not set by ipSetDefault */
1133
1134     return st;
1135 }
1136
1137 /*
1138  * cifdefaultroute - delete a default route through the address given.
1139  */
1140 int cifdefaultroute(int pd, u32_t l, u32_t g)
1141 {
1142     PPPControl *pc = &pppControl[pd];
1143     int st = 1;
1144     
1145         (void)l;
1146         (void)g;
1147     if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
1148         st = 0;
1149         PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));
1150     } else {
1151                 netif_set_default(NULL);
1152     }
1153
1154     return st;
1155 }
1156
1157 void
1158 pppMainWakeup(int pd)
1159 {
1160         PPPDEBUG((LOG_DEBUG, "pppMainWakeup: unit %d\n", pd));
1161         sio_read_abort(pppControl[pd].fd);
1162 }
1163
1164 /* these callbacks are necessary because lcp_* functions
1165    must be called in the same context as pppInput(),
1166    namely the tcpip_thread(), essentially because
1167    they manipulate timeouts which are thread-private
1168 */
1169
1170 static void
1171 pppStartCB(void *arg)
1172 {
1173     int pd = (int)arg;
1174
1175         PPPDEBUG((LOG_DEBUG, "pppStartCB: unit %d\n", pd));
1176     lcp_lowerup(pd);
1177     lcp_open(pd);      /* Start protocol */
1178 }
1179
1180 static void
1181 pppStopCB(void *arg)
1182 {
1183     int pd = (int)arg;
1184
1185         PPPDEBUG((LOG_DEBUG, "pppStopCB: unit %d\n", pd));
1186     lcp_close(pd, "User request");
1187 }
1188
1189 static void
1190 pppHupCB(void *arg)
1191 {
1192     int pd = (int)arg;
1193
1194         PPPDEBUG((LOG_DEBUG, "pppHupCB: unit %d\n", pd));
1195     lcp_lowerdown(pd);
1196     link_terminated(pd);
1197 }
1198 /**********************************/
1199 /*** LOCAL FUNCTION DEFINITIONS ***/
1200 /**********************************/
1201 /* The main PPP process function.  This implements the state machine according
1202  * to section 4 of RFC 1661: The Point-To-Point Protocol. */
1203 static void pppMain(void *arg)
1204 {
1205     int pd = (int)arg;
1206     struct pbuf *p;
1207     PPPControl* pc;
1208
1209     pc = &pppControl[pd];
1210
1211     p = pbuf_alloc(PBUF_RAW, PPP_MRU+PPP_HDRLEN, PBUF_RAM);
1212     if(!p) {
1213                 LWIP_ASSERT("p != NULL", p);
1214                 pc->errCode = PPPERR_ALLOC;
1215                 goto out;
1216     }
1217
1218     /*
1219      * Start the connection and handle incoming events (packet or timeout).
1220      */
1221         PPPDEBUG((LOG_INFO, "pppMain: unit %d: Connecting\n", pd));
1222     tcpip_callback(pppStartCB, arg);
1223     while (lcp_phase[pd] != PHASE_DEAD) {
1224         if (pc->kill_link) {
1225                 PPPDEBUG((LOG_DEBUG, "pppMainWakeup: unit %d kill_link -> pppStopCB\n", pd));
1226                 pc->errCode = PPPERR_USER;
1227                 /* This will leave us at PHASE_DEAD. */
1228                 tcpip_callback(pppStopCB, arg);
1229                 pc->kill_link = 0;
1230         }
1231         else if (pc->sig_hup) {
1232                 PPPDEBUG((LOG_DEBUG, "pppMainWakeup: unit %d sig_hup -> pppHupCB\n", pd));
1233                 pc->sig_hup = 0;
1234                 tcpip_callback(pppHupCB, arg);
1235         } else {
1236                 int c = sio_read(pc->fd, p->payload, p->len);
1237                 if(c > 0) {
1238                         pppInProc(pd, p->payload, c);
1239                 } else {
1240                     PPPDEBUG((LOG_DEBUG, "pppMainWakeup: unit %d sio_read len=%d returned %d\n", pd, p->len, c));
1241                     sys_msleep(250); /* give other tasks a chance to run */
1242                 }
1243         }
1244     }
1245         PPPDEBUG((LOG_INFO, "pppMain: unit %d: PHASE_DEAD\n", pd));
1246     pbuf_free(p);
1247
1248 out:
1249         PPPDEBUG((LOG_DEBUG, "pppMain: unit %d: linkStatusCB=%lx errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));
1250     if(pc->linkStatusCB)
1251             pc->linkStatusCB(pc->linkStatusCtx, pc->errCode ? pc->errCode : PPPERR_PROTOCOL, NULL);
1252
1253     pc->openFlag = 0;
1254 }
1255
1256 static struct pbuf *pppSingleBuf(struct pbuf *p)
1257 {
1258         struct pbuf *q, *b;
1259         u_char *pl;
1260
1261         if(p->tot_len == p->len)
1262                 return p;
1263
1264         q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
1265         if(!q) {
1266                 PPPDEBUG((LOG_ERR,
1267                         "pppSingleBuf: unable to alloc new buf (%d)\n", p->tot_len));
1268                 return p; /* live dangerously */
1269         }
1270
1271         for(b = p, pl = q->payload; b != NULL; b = b->next) {
1272                 memcpy(pl, b->payload, b->len);
1273                 pl += b->len;
1274         }
1275
1276         pbuf_free(p);
1277
1278         return q;
1279 }
1280
1281 struct pppInputHeader {
1282         int unit;
1283         u16_t proto;
1284 };
1285
1286 /*
1287  * Pass the processed input packet to the appropriate handler.
1288  * This function and all handlers run in the context of the tcpip_thread
1289  */
1290 static void pppInput(void *arg)
1291 {
1292         struct pbuf *nb = (struct pbuf *)arg;
1293     u16_t protocol;
1294     int pd;
1295
1296         pd = ((struct pppInputHeader *)nb->payload)->unit;
1297         protocol = ((struct pppInputHeader *)nb->payload)->proto;
1298
1299     pbuf_header(nb, -(int)sizeof(struct pppInputHeader));
1300
1301 #if LINK_STATS
1302     lwip_stats.link.recv++;
1303 #endif /* LINK_STATS */
1304
1305     /*
1306      * Toss all non-LCP packets unless LCP is OPEN.
1307      * Until we get past the authentication phase, toss all packets
1308      * except LCP, LQR and authentication packets.
1309      */
1310     if((lcp_phase[pd] <= PHASE_AUTHENTICATE) && (protocol != PPP_LCP)) {
1311             if(!((protocol == PPP_LQR) || (protocol == PPP_PAP) || (protocol == PPP_CHAP)) ||
1312                         (lcp_phase[pd] != PHASE_AUTHENTICATE)) {
1313                 PPPDEBUG((LOG_INFO, "pppInput: discarding proto 0x%04X in phase %d\n", protocol, lcp_phase[pd]));
1314                 goto drop;
1315             }
1316     }
1317
1318     switch(protocol) {
1319     case PPP_VJC_COMP:      /* VJ compressed TCP */
1320 #if VJ_SUPPORT > 0
1321         PPPDEBUG((LOG_INFO, "pppInput[%d]: vj_comp in pbuf len=%d\n", pd, nb->len));
1322         /*
1323          * Clip off the VJ header and prepend the rebuilt TCP/IP header and
1324          * pass the result to IP.
1325          */
1326         if (vj_uncompress_tcp(&nb, &pppControl[pd].vjComp) >= 0) {
1327             pppControl[pd].netif->input(nb, pppControl[pd].netif);
1328                         return;
1329         }
1330         /* Something's wrong so drop it. */
1331         PPPDEBUG((LOG_WARNING, "pppInput[%d]: Dropping VJ compressed\n", pd));
1332 #else
1333         /* No handler for this protocol so drop the packet. */
1334         PPPDEBUG((LOG_INFO, "pppInput[%d]: drop VJ Comp in %d:%s\n", pd, nb->len, nb->payload));
1335 #endif /* VJ_SUPPORT > 0 */
1336         break;
1337     case PPP_VJC_UNCOMP:    /* VJ uncompressed TCP */
1338 #if VJ_SUPPORT > 0
1339         PPPDEBUG((LOG_INFO, "pppInput[%d]: vj_un in pbuf len=%d\n", pd, nb->len));
1340         /*
1341          * Process the TCP/IP header for VJ header compression and then pass
1342          * the packet to IP.
1343          */
1344         if (vj_uncompress_uncomp(nb, &pppControl[pd].vjComp) >= 0) {
1345             pppControl[pd].netif->input(nb, pppControl[pd].netif);
1346                         return;
1347         }
1348         /* Something's wrong so drop it. */
1349         PPPDEBUG((LOG_WARNING, "pppInput[%d]: Dropping VJ uncompressed\n", pd));
1350 #else
1351         /* No handler for this protocol so drop the packet. */
1352         PPPDEBUG((LOG_INFO,
1353                     "pppInput[%d]: drop VJ UnComp in %d:.*H\n", 
1354                     pd, nb->len, LWIP_MIN(nb->len * 2, 40), nb->payload));
1355 #endif /* VJ_SUPPORT > 0 */
1356         break;
1357     case PPP_IP:            /* Internet Protocol */
1358         PPPDEBUG((LOG_INFO, "pppInput[%d]: ip in pbuf len=%d\n", pd, nb->len));
1359         pppControl[pd].netif->input(nb, pppControl[pd].netif);
1360                 return;
1361     default:
1362         {
1363                 struct protent *protp;
1364                 int i;
1365
1366                 /*
1367                  * Upcall the proper protocol input routine.
1368                  */
1369                 for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) {
1370                         if (protp->protocol == protocol && protp->enabled_flag) {
1371                                 PPPDEBUG((LOG_INFO, "pppInput[%d]: %s len=%d\n", pd, protp->name, nb->len));
1372                                 nb = pppSingleBuf(nb);
1373                                 (*protp->input)(pd, nb->payload, nb->len);
1374                                 goto out;
1375                         }
1376                 }
1377
1378                 /* No handler for this protocol so reject the packet. */
1379                 PPPDEBUG((LOG_INFO, "pppInput[%d]: rejecting unsupported proto 0x%04X len=%d\n", pd, protocol, nb->len));
1380                 pbuf_header(nb, sizeof(protocol));
1381 #if BYTE_ORDER == LITTLE_ENDIAN
1382                 protocol = htons(protocol);
1383                 memcpy(nb->payload, &protocol, sizeof(protocol));
1384 #endif
1385                 lcp_sprotrej(pd, nb->payload, nb->len);
1386         }
1387         break;
1388     }
1389
1390 drop:
1391 #if LINK_STATS
1392     lwip_stats.link.drop++;
1393 #endif
1394
1395 out:
1396     pbuf_free(nb);
1397     return;
1398 }
1399
1400
1401 /*
1402  * Drop the input packet.
1403  */
1404 static void pppDrop(PPPControl *pc)
1405 {
1406     if (pc->inHead != NULL) {
1407 #if 0       
1408         PPPDEBUG((LOG_INFO, "pppDrop: %d:%.*H\n", pc->inHead->len, min(60, pc->inHead->len * 2), pc->inHead->payload));
1409 #endif  
1410         PPPDEBUG((LOG_INFO, "pppDrop: pbuf len=%d\n", pc->inHead->len));
1411         if (pc->inTail && (pc->inTail != pc->inHead))
1412             pbuf_free(pc->inTail);
1413         pbuf_free(pc->inHead);
1414         pc->inHead = NULL;
1415         pc->inTail = NULL;
1416     }
1417 #if VJ_SUPPORT > 0
1418     vj_uncompress_err(&pc->vjComp);
1419 #endif
1420
1421 #if LINK_STATS
1422     lwip_stats.link.drop++;
1423 #endif /* LINK_STATS */
1424 }
1425
1426
1427 /*
1428  * Process a received octet string.
1429  */
1430 static void pppInProc(int pd, u_char *s, int l)
1431 {
1432     PPPControl *pc = &pppControl[pd];
1433     struct pbuf *nextNBuf;
1434     u_char curChar;
1435
1436     PPPDEBUG((LOG_DEBUG, "pppInProc[%d]: got %d bytes\n", pd, l));
1437     while (l-- > 0) {
1438         curChar = *s++;
1439         
1440         /* Handle special characters. */
1441         if (ESCAPE_P(pc->inACCM, curChar)) {
1442             /* Check for escape sequences. */
1443             /* XXX Note that this does not handle an escaped 0x5d character which
1444              * would appear as an escape character.  Since this is an ASCII ']'
1445              * and there is no reason that I know of to escape it, I won't complicate
1446              * the code to handle this case. GLL */
1447             if (curChar == PPP_ESCAPE)
1448                 pc->inEscaped = 1;
1449             /* Check for the flag character. */
1450             else if (curChar == PPP_FLAG) {
1451                 /* If this is just an extra flag character, ignore it. */
1452                 if (pc->inState <= PDADDRESS)
1453                     ;
1454                 /* If we haven't received the packet header, drop what has come in. */
1455                 else if (pc->inState < PDDATA) {
1456                     PPPDEBUG((LOG_WARNING,
1457                                 "pppInProc[%d]: Dropping incomplete packet %d\n", 
1458                                 pd, pc->inState));
1459 #if LINK_STATS
1460                                         lwip_stats.link.lenerr++;
1461 #endif
1462                     pppDrop(pc);
1463                 }
1464                 /* If the fcs is invalid, drop the packet. */
1465                 else if (pc->inFCS != PPP_GOODFCS) {
1466                     PPPDEBUG((LOG_INFO,
1467                                 "pppInProc[%d]: Dropping bad fcs 0x%04X proto=0x%04X\n", 
1468                                 pd, pc->inFCS, pc->inProtocol));
1469 #if LINK_STATS
1470                                         lwip_stats.link.chkerr++;
1471 #endif
1472                     pppDrop(pc);
1473                 }
1474                 /* Otherwise it's a good packet so pass it on. */
1475                 else {
1476                     
1477                     /* Trim off the checksum. */
1478                     if(pc->inTail->len >= 2) {
1479                         pc->inTail->len -= 2;
1480
1481                         pc->inTail->tot_len = pc->inTail->len;
1482                         if (pc->inTail != pc->inHead) {
1483                             pbuf_cat(pc->inHead, pc->inTail);
1484                         }
1485                     } else {
1486                         pc->inTail->tot_len = pc->inTail->len;
1487                         if (pc->inTail != pc->inHead) {
1488                             pbuf_cat(pc->inHead, pc->inTail);
1489                         }
1490
1491                         pbuf_realloc(pc->inHead, pc->inHead->tot_len - 2);
1492                     }
1493
1494                     /* Dispatch the packet thereby consuming it. */
1495                     if(tcpip_callback(pppInput, pc->inHead) != ERR_OK) {
1496                         PPPDEBUG((LOG_ERR,
1497                                     "pppInProc[%d]: tcpip_callback() failed, dropping packet\n", pd));
1498                         pbuf_free(pc->inHead);
1499 #if LINK_STATS
1500                         lwip_stats.link.drop++;
1501 #endif
1502                     }
1503                     pc->inHead = NULL;
1504                     pc->inTail = NULL;
1505                 }
1506                     
1507                 /* Prepare for a new packet. */
1508                 pc->inFCS = PPP_INITFCS;
1509                 pc->inState = PDADDRESS;
1510                 pc->inEscaped = 0;
1511             }
1512             /* Other characters are usually control characters that may have
1513              * been inserted by the physical layer so here we just drop them. */
1514             else {
1515                 PPPDEBUG((LOG_WARNING,
1516                             "pppInProc[%d]: Dropping ACCM char <%d>\n", pd, curChar));
1517             }
1518         }
1519         /* Process other characters. */
1520         else {
1521             /* Unencode escaped characters. */
1522             if (pc->inEscaped) {
1523                 pc->inEscaped = 0;
1524                 curChar ^= PPP_TRANS;
1525             }
1526             
1527             /* Process character relative to current state. */
1528             switch(pc->inState) {
1529             case PDIDLE:                    /* Idle state - waiting. */
1530                 /* Drop the character if it's not 0xff
1531                  * we would have processed a flag character above. */
1532                 if (curChar != PPP_ALLSTATIONS) {
1533                         break;
1534                                 }
1535
1536                                 /* Fall through */
1537             case PDSTART:                   /* Process start flag. */
1538                 /* Prepare for a new packet. */
1539                 pc->inFCS = PPP_INITFCS;
1540
1541                                 /* Fall through */
1542             case PDADDRESS:                 /* Process address field. */
1543                 if (curChar == PPP_ALLSTATIONS) {
1544                     pc->inState = PDCONTROL;
1545                     break;
1546                 }
1547                 /* Else assume compressed address and control fields so
1548                  * fall through to get the protocol... */
1549             case PDCONTROL:                 /* Process control field. */
1550                 /* If we don't get a valid control code, restart. */
1551                 if (curChar == PPP_UI) {
1552                     pc->inState = PDPROTOCOL1;
1553                         break;
1554                 }
1555 #if 0
1556                 else {
1557                     PPPDEBUG((LOG_WARNING,
1558                                 "pppInProc[%d]: Invalid control <%d>\n", pd, curChar));
1559                     pc->inState = PDSTART;
1560                 }
1561 #endif
1562             case PDPROTOCOL1:               /* Process protocol field 1. */
1563                 /* If the lower bit is set, this is the end of the protocol
1564                  * field. */
1565                 if (curChar & 1) {
1566                     pc->inProtocol = curChar;
1567                     pc->inState = PDDATA;
1568                 }
1569                 else {
1570                     pc->inProtocol = (u_int)curChar << 8;
1571                     pc->inState = PDPROTOCOL2;
1572                 }
1573                 break;
1574             case PDPROTOCOL2:               /* Process protocol field 2. */
1575                 pc->inProtocol |= curChar;
1576                 pc->inState = PDDATA;
1577                 break;
1578             case PDDATA:                    /* Process data byte. */
1579                 /* Make space to receive processed data. */
1580                 if (pc->inTail == NULL || pc->inTail->len == PBUF_POOL_BUFSIZE) {
1581                     if(pc->inTail) {
1582                         pc->inTail->tot_len = pc->inTail->len;
1583                         if (pc->inTail != pc->inHead) {
1584                             pbuf_cat(pc->inHead, pc->inTail);
1585                         }
1586                     }
1587                     /* If we haven't started a packet, we need a packet header. */
1588                     nextNBuf = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
1589                     if (nextNBuf == NULL) {
1590                         /* No free buffers.  Drop the input packet and let the
1591                          * higher layers deal with it.  Continue processing
1592                          * the received pbuf chain in case a new packet starts. */
1593                         PPPDEBUG((LOG_ERR, "pppInProc[%d]: NO FREE MBUFS!\n", pd));
1594 #if LINK_STATS
1595                                                 lwip_stats.link.memerr++;
1596 #endif /* LINK_STATS */
1597                         pppDrop(pc);
1598                         pc->inState = PDSTART;  /* Wait for flag sequence. */
1599                         break;
1600                     }
1601                     if (pc->inHead == NULL) {
1602                         struct pppInputHeader *pih = nextNBuf->payload;
1603
1604                         pih->unit = pd;
1605                         pih->proto = pc->inProtocol;
1606
1607                         nextNBuf->len += sizeof(*pih);
1608
1609                         pc->inHead = nextNBuf;
1610                     }
1611                     pc->inTail = nextNBuf;
1612                 }
1613                 /* Load character into buffer. */
1614                 ((u_char*)pc->inTail->payload)[pc->inTail->len++] = curChar;
1615                 break;
1616             }
1617
1618             /* update the frame check sequence number. */
1619             pc->inFCS = PPP_FCS(pc->inFCS, curChar);
1620         }
1621     }
1622         avRandomize();
1623 }
1624
1625 #endif /* PPP_SUPPORT */