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